blob: a03c1fea5093e17305424d9d4ec730d41b0cca1a [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d1982009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
Michael Thiessenfd6919b2020-12-08 20:44:01129 ),
130 (
131 'android.support.test.rule.ActivityTestRule;',
132 (
133 'Do not use ActivityTestRule, use '
134 'org.chromium.base.test.BaseActivityTestRule instead.',
135 ),
136 (
137 'components/cronet/',
138 )
Michael Thiessened631912020-08-07 19:01:31139 )
Michael Thiessen44457642020-02-06 00:24:15140)
wnwenbdc444e2016-05-25 13:44:15141
Daniel Bratell609102be2019-03-27 20:53:21142# Format: Sequence of tuples containing:
143# * String pattern or, if starting with a slash, a regular expression.
144# * Sequence of strings to show when the pattern matches.
145# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41146_BANNED_JAVA_FUNCTIONS = (
147 (
148 'StrictMode.allowThreadDiskReads()',
149 (
150 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
151 'directly.',
152 ),
153 False,
154 ),
155 (
156 'StrictMode.allowThreadDiskWrites()',
157 (
158 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
159 'directly.',
160 ),
161 False,
162 ),
Michael Thiessen0f2547e2020-07-27 21:55:36163 (
164 '.waitForIdleSync()',
165 (
166 'Do not use waitForIdleSync as it masks underlying issues. There is '
167 'almost always something else you should wait on instead.',
168 ),
169 False,
170 ),
Eric Stevensona9a980972017-09-23 00:04:41171)
172
Daniel Bratell609102be2019-03-27 20:53:21173# Format: Sequence of tuples containing:
174# * String pattern or, if starting with a slash, a regular expression.
175# * Sequence of strings to show when the pattern matches.
176# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59177_BANNED_OBJC_FUNCTIONS = (
178 (
179 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20180 (
181 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59182 'prohibited. Please use CrTrackingArea instead.',
183 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
184 ),
185 False,
186 ),
187 (
[email protected]eaae1972014-04-16 04:17:26188 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20189 (
190 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59191 'instead.',
192 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
193 ),
194 False,
195 ),
196 (
197 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20198 (
199 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59200 'Please use |convertPoint:(point) fromView:nil| instead.',
201 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
202 ),
203 True,
204 ),
205 (
206 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59209 'Please use |convertPoint:(point) toView:nil| instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 True,
213 ),
214 (
215 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59218 'Please use |convertRect:(point) fromView:nil| instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 True,
222 ),
223 (
224 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertRect:(point) toView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
232 (
233 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertSize:(point) fromView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
241 (
242 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertSize:(point) toView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
jif65398702016-10-27 10:19:48250 (
251 r"/\s+UTF8String\s*]",
252 (
253 'The use of -[NSString UTF8String] is dangerous as it can return null',
254 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
255 'Please use |SysNSStringToUTF8| instead.',
256 ),
257 True,
258 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34259 (
260 r'__unsafe_unretained',
261 (
262 'The use of __unsafe_unretained is almost certainly wrong, unless',
263 'when interacting with NSFastEnumeration or NSInvocation.',
264 'Please use __weak in files build with ARC, nothing otherwise.',
265 ),
266 False,
267 ),
Avi Drissman7382afa02019-04-29 23:27:13268 (
269 'freeWhenDone:NO',
270 (
271 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
272 'Foundation types is prohibited.',
273 ),
274 True,
275 ),
[email protected]127f18ec2012-06-16 05:05:59276)
277
Daniel Bratell609102be2019-03-27 20:53:21278# Format: Sequence of tuples containing:
279# * String pattern or, if starting with a slash, a regular expression.
280# * Sequence of strings to show when the pattern matches.
281# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54282_BANNED_IOS_OBJC_FUNCTIONS = (
283 (
284 r'/\bTEST[(]',
285 (
286 'TEST() macro should not be used in Objective-C++ code as it does not ',
287 'drain the autorelease pool at the end of the test. Use TEST_F() ',
288 'macro instead with a fixture inheriting from PlatformTest (or a ',
289 'typedef).'
290 ),
291 True,
292 ),
293 (
294 r'/\btesting::Test\b',
295 (
296 'testing::Test should not be used in Objective-C++ code as it does ',
297 'not drain the autorelease pool at the end of the test. Use ',
298 'PlatformTest instead.'
299 ),
300 True,
301 ),
302)
303
Peter K. Lee6c03ccff2019-07-15 14:40:05304# Format: Sequence of tuples containing:
305# * String pattern or, if starting with a slash, a regular expression.
306# * Sequence of strings to show when the pattern matches.
307# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
308_BANNED_IOS_EGTEST_FUNCTIONS = (
309 (
310 r'/\bEXPECT_OCMOCK_VERIFY\b',
311 (
312 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
313 'it is meant for GTests. Use [mock verify] instead.'
314 ),
315 True,
316 ),
317)
318
danakj7a2b7082019-05-21 21:13:51319# Directories that contain deprecated Bind() or Callback types.
320# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36321# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51322# echo "-- $i"
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/',
Alexander Cooperd1244c582021-01-26 02:25:27355 '^media/blink/webmediaplayer_impl.cc',
356 '^media/blink/webmediaplayer_impl.h',
danakj7a2b7082019-05-21 21:13:51357 '^ppapi/proxy/',
Alexander Cooperb3f1af662021-02-01 19:47:26358 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
359 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51360 '^tools/clang/base_bind_rewriters/', # Intentional.
361 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51362))
[email protected]127f18ec2012-06-16 05:05:59363
Alexander Cooper46a92712021-01-30 00:00:20364# Directories that contain deprecated CallbackList types.
365# Find sub-directories from a given directory by running:
366# for i in `find . -maxdepth 1 -type d|sort`; do
367# echo "-- $i"
368# (cd $i; git grep -nP 'base::CallbackList<'|wc -l)
369# done
370#
371# TODO(crbug.com/1113007): Remove (or narrow the scope of) paths from this list
372# when they have been converted to modern callback list types (OnceCallback,
373# RepeatingCallback) in order to enable presubmit checks for them and prevent
374# regressions.
375_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST = '|'.join((
376 r'^chrome/browser/android/oom_intervention/near_oom_monitor\.h',
377 r'^chrome/browser/ash/account_manager/child_account_type_changed_user_data\.h', # pylint: disable=line-too-long
378 r'^chrome/browser/browser_switcher/',
379 r'^chrome/browser/chromeos/',
380 r'^chrome/browser/media/router/providers/cast/',
381 r'^chrome/brwoser/sessions/session_restore\.cc',
382 r'^chrome/browser/supervised_user/',
383 r'^chrome/browser/ui/',
384 r'^chromecast/external_mojo/external_service_support/',
385 r'^components/captive_portal/content/captive_portal_service\.h',
386 r'^components/keyed_service/core/keyed_service_shutdown_notifier\.h',
387 r'^components/media_router/browser/',
388 r'^components/ntp_tils/custom_links_manager_impl\.h',
389 r'^components/password_manager/core/browser/hash_password_manager\.h',
390 r'^components/suggestions/suggestions_service\.h',
391 r'^components/sync_device_info/',
392 r'^components/sync_sessions/session_sync_service_impl\.h',
393 r'^components/zoom/zoom_event_manager\.h',
394 r'^content/browser/host_zoom_map_impl\.h',
395 r'^content/browser/network_service_instance_impl\.h',
396 r'^content/browser/rendeer_host/render_process_host_impl\.cc',
397 r'^extensions/test/extension_test_notification_observer\.h',
398 r'^ios/chrome/browser/tabs/tab_parenting_global_observer\.h',
399 r'^ios/net/cookies/cookie_store_ios\.h',
400 r'^net/cookies/cookie_monster_change_dispatcher\.h',
401 r'^remoting/signaling/messaging_client\.h',
402 r'^services/device/battery/battery_status_service\.h',
403 r'^services/device/geolocation/',
404 r'^weblayer/browser/i18n_util\.cc',
405 r'^weblayer/public/cookie_manager\.h',
406))
407
Daniel Bratell609102be2019-03-27 20:53:21408# Format: Sequence of tuples containing:
409# * String pattern or, if starting with a slash, a regular expression.
410# * Sequence of strings to show when the pattern matches.
411# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
412# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59413_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20414 (
Peter Kasting94a56c42019-10-25 21:54:04415 r'/\busing namespace ',
416 (
417 'Using directives ("using namespace x") are banned by the Google Style',
418 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
419 'Explicitly qualify symbols or use using declarations ("using x::foo").',
420 ),
421 True,
422 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
423 ),
Antonio Gomes07300d02019-03-13 20:59:57424 # Make sure that gtest's FRIEND_TEST() macro is not used; the
425 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
426 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53427 (
[email protected]23e6cbc2012-06-16 18:51:20428 'FRIEND_TEST(',
429 (
[email protected]e3c945502012-06-26 20:01:49430 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20431 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
432 ),
433 False,
[email protected]7345da02012-11-27 14:31:49434 (),
[email protected]23e6cbc2012-06-16 18:51:20435 ),
436 (
tomhudsone2c14d552016-05-26 17:07:46437 'setMatrixClip',
438 (
439 'Overriding setMatrixClip() is prohibited; ',
440 'the base function is deprecated. ',
441 ),
442 True,
443 (),
444 ),
445 (
[email protected]52657f62013-05-20 05:30:31446 'SkRefPtr',
447 (
448 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22449 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31450 ),
451 True,
452 (),
453 ),
454 (
455 'SkAutoRef',
456 (
457 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22458 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31459 ),
460 True,
461 (),
462 ),
463 (
464 'SkAutoTUnref',
465 (
466 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22467 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31468 ),
469 True,
470 (),
471 ),
472 (
473 'SkAutoUnref',
474 (
475 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
476 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22477 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31478 ),
479 True,
480 (),
481 ),
[email protected]d89eec82013-12-03 14:10:59482 (
483 r'/HANDLE_EINTR\(.*close',
484 (
485 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
486 'descriptor will be closed, and it is incorrect to retry the close.',
487 'Either call close directly and ignore its return value, or wrap close',
488 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
489 ),
490 True,
491 (),
492 ),
493 (
494 r'/IGNORE_EINTR\((?!.*close)',
495 (
496 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
497 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
498 ),
499 True,
500 (
501 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04502 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
503 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59504 ),
505 ),
[email protected]ec5b3f02014-04-04 18:43:43506 (
507 r'/v8::Extension\(',
508 (
509 'Do not introduce new v8::Extensions into the code base, use',
510 'gin::Wrappable instead. See http://crbug.com/334679',
511 ),
512 True,
[email protected]f55c90ee62014-04-12 00:50:03513 (
Egor Paskoce145c42018-09-28 19:31:04514 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03515 ),
[email protected]ec5b3f02014-04-04 18:43:43516 ),
skyostilf9469f72015-04-20 10:38:52517 (
jame2d1a952016-04-02 00:27:10518 '#pragma comment(lib,',
519 (
520 'Specify libraries to link with in build files and not in the source.',
521 ),
522 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41523 (
tzik3f295992018-12-04 20:32:23524 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04525 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41526 ),
jame2d1a952016-04-02 00:27:10527 ),
fdorayc4ac18d2017-05-01 21:39:59528 (
Gabriel Charette7cc6c432018-04-25 20:52:02529 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59530 (
531 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
532 ),
533 False,
534 (),
535 ),
536 (
Gabriel Charette7cc6c432018-04-25 20:52:02537 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59538 (
539 'Consider using THREAD_CHECKER macros instead of the class directly.',
540 ),
541 False,
542 (),
543 ),
dbeamb6f4fde2017-06-15 04:03:06544 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06545 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
546 (
547 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
548 'deprecated (http://crbug.com/634507). Please avoid converting away',
549 'from the Time types in Chromium code, especially if any math is',
550 'being done on time values. For interfacing with platform/library',
551 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
552 'type converter methods instead. For faking TimeXXX values (for unit',
553 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
554 'other use cases, please contact base/time/OWNERS.',
555 ),
556 False,
557 (),
558 ),
559 (
dbeamb6f4fde2017-06-15 04:03:06560 'CallJavascriptFunctionUnsafe',
561 (
562 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
563 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
564 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
565 ),
566 False,
567 (
Egor Paskoce145c42018-09-28 19:31:04568 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
569 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
570 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06571 ),
572 ),
dskiba1474c2bfd62017-07-20 02:19:24573 (
574 'leveldb::DB::Open',
575 (
576 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
577 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
578 "Chrome's tracing, making their memory usage visible.",
579 ),
580 True,
581 (
582 r'^third_party/leveldatabase/.*\.(cc|h)$',
583 ),
Gabriel Charette0592c3a2017-07-26 12:02:04584 ),
585 (
Chris Mumfordc38afb62017-10-09 17:55:08586 'leveldb::NewMemEnv',
587 (
588 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58589 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
590 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08591 ),
592 True,
593 (
594 r'^third_party/leveldatabase/.*\.(cc|h)$',
595 ),
596 ),
597 (
Gabriel Charetted9839bc2017-07-29 14:17:47598 'RunLoop::QuitCurrent',
599 (
Robert Liao64b7ab22017-08-04 23:03:43600 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
601 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47602 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41603 False,
Gabriel Charetted9839bc2017-07-29 14:17:47604 (),
Gabriel Charettea44975052017-08-21 23:14:04605 ),
606 (
607 'base::ScopedMockTimeMessageLoopTaskRunner',
608 (
Gabriel Charette87cc1af2018-04-25 20:52:51609 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11610 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51611 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
612 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
613 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04614 ),
Gabriel Charette87cc1af2018-04-25 20:52:51615 False,
Gabriel Charettea44975052017-08-21 23:14:04616 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57617 ),
618 (
Dave Tapuska98199b612019-07-10 13:30:44619 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57620 (
621 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02622 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57623 ),
624 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16625 # Abseil's benchmarks never linked into chrome.
626 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38627 ),
628 (
Peter Kasting991618a62019-06-17 22:00:09629 r'/\bstd::stoi\b',
630 (
631 'std::stoi uses exceptions to communicate results. ',
632 'Use base::StringToInt() instead.',
633 ),
634 True,
635 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
636 ),
637 (
638 r'/\bstd::stol\b',
639 (
640 'std::stol uses exceptions to communicate results. ',
641 'Use base::StringToInt() instead.',
642 ),
643 True,
644 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
645 ),
646 (
647 r'/\bstd::stoul\b',
648 (
649 'std::stoul uses exceptions to communicate results. ',
650 'Use base::StringToUint() instead.',
651 ),
652 True,
653 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
654 ),
655 (
656 r'/\bstd::stoll\b',
657 (
658 'std::stoll uses exceptions to communicate results. ',
659 'Use base::StringToInt64() instead.',
660 ),
661 True,
662 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
663 ),
664 (
665 r'/\bstd::stoull\b',
666 (
667 'std::stoull uses exceptions to communicate results. ',
668 'Use base::StringToUint64() instead.',
669 ),
670 True,
671 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
672 ),
673 (
674 r'/\bstd::stof\b',
675 (
676 'std::stof uses exceptions to communicate results. ',
677 'For locale-independent values, e.g. reading numbers from disk',
678 'profiles, use base::StringToDouble().',
679 'For user-visible values, parse using ICU.',
680 ),
681 True,
682 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
683 ),
684 (
685 r'/\bstd::stod\b',
686 (
687 'std::stod uses exceptions to communicate results. ',
688 'For locale-independent values, e.g. reading numbers from disk',
689 'profiles, use base::StringToDouble().',
690 'For user-visible values, parse using ICU.',
691 ),
692 True,
693 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
694 ),
695 (
696 r'/\bstd::stold\b',
697 (
698 'std::stold uses exceptions to communicate results. ',
699 'For locale-independent values, e.g. reading numbers from disk',
700 'profiles, use base::StringToDouble().',
701 'For user-visible values, parse using ICU.',
702 ),
703 True,
704 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
705 ),
706 (
Daniel Bratell69334cc2019-03-26 11:07:45707 r'/\bstd::to_string\b',
708 (
709 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09710 'For locale-independent strings, e.g. writing numbers to disk',
711 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45712 'For user-visible strings, use base::FormatNumber() and',
713 'the related functions in base/i18n/number_formatting.h.',
714 ),
Peter Kasting991618a62019-06-17 22:00:09715 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21716 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45717 ),
718 (
719 r'/\bstd::shared_ptr\b',
720 (
721 'std::shared_ptr should not be used. Use scoped_refptr instead.',
722 ),
723 True,
Alex Chau9eb03cdd52020-07-13 21:04:57724 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
725 'array_buffer_contents\.(cc|h)',
726 # Needed for interop with third-party library
727 'chrome/services/sharing/nearby/',
728 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21729 ),
730 (
Peter Kasting991618a62019-06-17 22:00:09731 r'/\bstd::weak_ptr\b',
732 (
733 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
734 ),
735 True,
736 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
737 ),
738 (
Daniel Bratell609102be2019-03-27 20:53:21739 r'/\blong long\b',
740 (
741 'long long is banned. Use stdint.h if you need a 64 bit number.',
742 ),
743 False, # Only a warning since it is already used.
744 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
745 ),
746 (
747 r'/\bstd::bind\b',
748 (
749 'std::bind is banned because of lifetime risks.',
750 'Use base::BindOnce or base::BindRepeating instead.',
751 ),
752 True,
753 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
754 ),
755 (
756 r'/\b#include <chrono>\b',
757 (
758 '<chrono> overlaps with Time APIs in base. Keep using',
759 'base classes.',
760 ),
761 True,
762 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
763 ),
764 (
765 r'/\b#include <exception>\b',
766 (
767 'Exceptions are banned and disabled in Chromium.',
768 ),
769 True,
770 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
771 ),
772 (
773 r'/\bstd::function\b',
774 (
775 'std::function is banned. Instead use base::Callback which directly',
776 'supports Chromium\'s weak pointers, ref counting and more.',
777 ),
Peter Kasting991618a62019-06-17 22:00:09778 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21779 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
780 ),
781 (
782 r'/\b#include <random>\b',
783 (
784 'Do not use any random number engines from <random>. Instead',
785 'use base::RandomBitGenerator.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
789 ),
790 (
Tom Andersona95e12042020-09-09 23:08:00791 r'/\b#include <X11/',
792 (
793 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
794 ),
795 True,
796 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
797 ),
798 (
Daniel Bratell609102be2019-03-27 20:53:21799 r'/\bstd::ratio\b',
800 (
801 'std::ratio is banned by the Google Style Guide.',
802 ),
803 True,
804 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45805 ),
806 (
Francois Doray43670e32017-09-27 12:40:38807 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
808 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
809 (
810 'Use the new API in base/threading/thread_restrictions.h.',
811 ),
Gabriel Charette04b138f2018-08-06 00:03:22812 False,
Francois Doray43670e32017-09-27 12:40:38813 (),
814 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38815 (
danakj7a2b7082019-05-21 21:13:51816 r'/\bbase::Bind\(',
817 (
818 'Please use base::Bind{Once,Repeating} instead',
819 'of base::Bind. (crbug.com/714018)',
820 ),
821 False,
Erik Staaba737d7602019-11-25 18:41:07822 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51823 ),
824 (
825 r'/\bbase::Callback[<:]',
826 (
827 'Please use base::{Once,Repeating}Callback instead',
828 'of base::Callback. (crbug.com/714018)',
829 ),
830 False,
Erik Staaba737d7602019-11-25 18:41:07831 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51832 ),
833 (
834 r'/\bbase::Closure\b',
835 (
836 'Please use base::{Once,Repeating}Closure instead',
837 'of base::Closure. (crbug.com/714018)',
838 ),
839 False,
Erik Staaba737d7602019-11-25 18:41:07840 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51841 ),
842 (
Alex Turnerb3ea38c2020-11-25 18:03:07843 r'/\bbase::CancelableCallback[<:]',
844 (
845 'Please use base::Cancelable{Once,Repeating}Callback instead',
846 'of base::CancelableCallback. (crbug.com/714018)',
847 ),
848 False,
849 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
850 ),
851 (
852 r'/\bbase::CancelableClosure\b',
853 (
854 'Please use base::Cancelable{Once,Repeating}Closure instead',
855 'of base::CancelableClosure. (crbug.com/714018)',
856 ),
857 False,
858 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
859 ),
860 (
Alexander Cooper46a92712021-01-30 00:00:20861 r'/\bbase::CallbackList<',
862 (
863 'Please use base::{Once,Repeating}CallbackList instead',
864 'of base::CallbackList. (crbug.com/1113007)'
865 ),
866 False,
867 (_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST,),
868 ),
869 (
Michael Giuffrida7f93d6922019-04-19 14:39:58870 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19871 (
872 'RunMessageLoop is deprecated, use RunLoop instead.',
873 ),
874 False,
875 (),
876 ),
877 (
Dave Tapuska98199b612019-07-10 13:30:44878 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19879 (
880 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
881 ),
882 False,
883 (),
884 ),
885 (
Dave Tapuska98199b612019-07-10 13:30:44886 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19887 (
888 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
889 "if you're convinced you need this.",
890 ),
891 False,
892 (),
893 ),
894 (
Dave Tapuska98199b612019-07-10 13:30:44895 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19896 (
897 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04898 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19899 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
900 'async events instead of flushing threads.',
901 ),
902 False,
903 (),
904 ),
905 (
906 r'MessageLoopRunner',
907 (
908 'MessageLoopRunner is deprecated, use RunLoop instead.',
909 ),
910 False,
911 (),
912 ),
913 (
Dave Tapuska98199b612019-07-10 13:30:44914 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19915 (
916 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
917 "gab@ if you found a use case where this is the only solution.",
918 ),
919 False,
920 (),
921 ),
922 (
Victor Costane48a2e82019-03-15 22:02:34923 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16924 (
Victor Costane48a2e82019-03-15 22:02:34925 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16926 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
927 ),
928 True,
929 (
930 r'^sql/initialization\.(cc|h)$',
931 r'^third_party/sqlite/.*\.(c|cc|h)$',
932 ),
933 ),
Matt Menke7f520a82018-03-28 21:38:37934 (
Dave Tapuska98199b612019-07-10 13:30:44935 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47936 (
937 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
938 'base::RandomShuffle instead.'
939 ),
940 True,
941 (),
942 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24943 (
944 'ios/web/public/test/http_server',
945 (
946 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
947 ),
948 False,
949 (),
950 ),
Robert Liao764c9492019-01-24 18:46:28951 (
952 'GetAddressOf',
953 (
954 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53955 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11956 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53957 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28958 ),
959 True,
960 (),
961 ),
Antonio Gomes07300d02019-03-13 20:59:57962 (
Ben Lewisa9514602019-04-29 17:53:05963 'SHFileOperation',
964 (
965 'SHFileOperation was deprecated in Windows Vista, and there are less ',
966 'complex functions to achieve the same goals. Use IFileOperation for ',
967 'any esoteric actions instead.'
968 ),
969 True,
970 (),
971 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18972 (
Cliff Smolinsky81951642019-04-30 21:39:51973 'StringFromGUID2',
974 (
975 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24976 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51977 ),
978 True,
979 (
980 r'/base/win/win_util_unittest.cc'
981 ),
982 ),
983 (
984 'StringFromCLSID',
985 (
986 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24987 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51988 ),
989 True,
990 (
991 r'/base/win/win_util_unittest.cc'
992 ),
993 ),
994 (
Avi Drissman7382afa02019-04-29 23:27:13995 'kCFAllocatorNull',
996 (
997 'The use of kCFAllocatorNull with the NoCopy creation of ',
998 'CoreFoundation types is prohibited.',
999 ),
1000 True,
1001 (),
1002 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291003 (
1004 'mojo::ConvertTo',
1005 (
1006 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1007 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1008 'StringTraits if you would like to convert between custom types and',
1009 'the wire format of mojom types.'
1010 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221011 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291012 (
Wezf89dec092019-09-11 19:38:331013 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1014 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291015 r'^third_party/blink/.*\.(cc|h)$',
1016 r'^content/renderer/.*\.(cc|h)$',
1017 ),
1018 ),
Robert Liao1d78df52019-11-11 20:02:011019 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161020 'GetInterfaceProvider',
1021 (
1022 'InterfaceProvider is deprecated.',
1023 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1024 'or Platform::GetBrowserInterfaceBroker.'
1025 ),
1026 False,
1027 (),
1028 ),
1029 (
Robert Liao1d78df52019-11-11 20:02:011030 'CComPtr',
1031 (
1032 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1033 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1034 'details.'
1035 ),
1036 False,
1037 (),
1038 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201039 (
1040 r'/\b(IFACE|STD)METHOD_?\(',
1041 (
1042 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1043 'Instead, always use IFACEMETHODIMP in the declaration.'
1044 ),
1045 False,
1046 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1047 ),
Allen Bauer53b43fb12020-03-12 17:21:471048 (
1049 'set_owned_by_client',
1050 (
1051 'set_owned_by_client is deprecated.',
1052 'views::View already owns the child views by default. This introduces ',
1053 'a competing ownership model which makes the code difficult to reason ',
1054 'about. See http://crbug.com/1044687 for more details.'
1055 ),
1056 False,
1057 (),
1058 ),
Eric Secklerbe6f48d2020-05-06 18:09:121059 (
1060 r'/\bTRACE_EVENT_ASYNC_',
1061 (
1062 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1063 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1064 ),
1065 False,
1066 (
1067 r'^base/trace_event/.*',
1068 r'^base/tracing/.*',
1069 ),
1070 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261071 (
1072 r'/\bScopedObserver',
1073 (
1074 'ScopedObserver is deprecated.',
1075 'Please use base::ScopedObservation for observing a single source,',
1076 'or base::ScopedMultiSourceObservation for observing multple sources',
1077 ),
1078 False,
1079 (),
1080 ),
[email protected]127f18ec2012-06-16 05:05:591081)
1082
Mario Sanchez Prada2472cab2019-09-18 10:58:311083# Format: Sequence of tuples containing:
1084# * String pattern or, if starting with a slash, a regular expression.
1085# * Sequence of strings to show when the pattern matches.
1086_DEPRECATED_MOJO_TYPES = (
1087 (
1088 r'/\bmojo::AssociatedBinding\b',
1089 (
1090 'mojo::AssociatedBinding<Interface> is deprecated.',
1091 'Use mojo::AssociatedReceiver<Interface> instead.',
1092 ),
1093 ),
1094 (
1095 r'/\bmojo::AssociatedBindingSet\b',
1096 (
1097 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1098 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1099 ),
1100 ),
1101 (
1102 r'/\bmojo::AssociatedInterfacePtr\b',
1103 (
1104 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1105 'Use mojo::AssociatedRemote<Interface> instead.',
1106 ),
1107 ),
1108 (
1109 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1110 (
1111 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1112 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1113 ),
1114 ),
1115 (
1116 r'/\bmojo::AssociatedInterfaceRequest\b',
1117 (
1118 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1119 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1120 ),
1121 ),
1122 (
1123 r'/\bmojo::Binding\b',
1124 (
1125 'mojo::Binding<Interface> is deprecated.',
1126 'Use mojo::Receiver<Interface> instead.',
1127 ),
1128 ),
1129 (
1130 r'/\bmojo::BindingSet\b',
1131 (
1132 'mojo::BindingSet<Interface> is deprecated.',
1133 'Use mojo::ReceiverSet<Interface> instead.',
1134 ),
1135 ),
1136 (
1137 r'/\bmojo::InterfacePtr\b',
1138 (
1139 'mojo::InterfacePtr<Interface> is deprecated.',
1140 'Use mojo::Remote<Interface> instead.',
1141 ),
1142 ),
1143 (
1144 r'/\bmojo::InterfacePtrInfo\b',
1145 (
1146 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1147 'Use mojo::PendingRemote<Interface> instead.',
1148 ),
1149 ),
1150 (
1151 r'/\bmojo::InterfaceRequest\b',
1152 (
1153 'mojo::InterfaceRequest<Interface> is deprecated.',
1154 'Use mojo::PendingReceiver<Interface> instead.',
1155 ),
1156 ),
1157 (
1158 r'/\bmojo::MakeRequest\b',
1159 (
1160 'mojo::MakeRequest is deprecated.',
1161 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1162 ),
1163 ),
1164 (
1165 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1166 (
1167 'mojo::MakeRequest is deprecated.',
1168 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181169 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311170 ),
1171 ),
1172 (
1173 r'/\bmojo::MakeStrongBinding\b',
1174 (
1175 'mojo::MakeStrongBinding is deprecated.',
1176 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1177 'mojo::MakeSelfOwnedReceiver() instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::MakeStrongAssociatedBinding\b',
1182 (
1183 'mojo::MakeStrongAssociatedBinding is deprecated.',
1184 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1185 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1186 ),
1187 ),
1188 (
Gyuyoung Kim4952ba62020-07-07 07:33:441189 r'/\bmojo::StrongAssociatedBinding\b',
1190 (
1191 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1192 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1193 ),
1194 ),
1195 (
1196 r'/\bmojo::StrongBinding\b',
1197 (
1198 'mojo::StrongBinding<Interface> is deprecated.',
1199 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1200 ),
1201 ),
1202 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311203 r'/\bmojo::StrongAssociatedBindingSet\b',
1204 (
1205 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1206 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::StrongBindingSet\b',
1211 (
1212 'mojo::StrongBindingSet<Interface> is deprecated.',
1213 'Use mojo::UniqueReceiverSet<Interface> instead.',
1214 ),
1215 ),
1216)
wnwenbdc444e2016-05-25 13:44:151217
mlamouria82272622014-09-16 18:45:041218_IPC_ENUM_TRAITS_DEPRECATED = (
1219 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501220 'See http://www.chromium.org/Home/chromium-security/education/'
1221 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041222
Stephen Martinis97a394142018-06-07 23:06:051223_LONG_PATH_ERROR = (
1224 'Some files included in this CL have file names that are too long (> 200'
1225 ' characters). If committed, these files will cause issues on Windows. See'
1226 ' https://crbug.com/612667 for more details.'
1227)
1228
Shenghua Zhangbfaa38b82017-11-16 21:58:021229_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041230 r".*[\\/]BuildHooksAndroidImpl\.java",
1231 r".*[\\/]LicenseContentProvider\.java",
1232 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281233 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021234]
[email protected]127f18ec2012-06-16 05:05:591235
Mohamed Heikald048240a2019-11-12 16:57:371236# List of image extensions that are used as resources in chromium.
1237_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1238
Sean Kau46e29bc2017-08-28 16:31:161239# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401240_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041241 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401242 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041243 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1244 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041245 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431246 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161247]
1248
1249
[email protected]b00342e7f2013-03-26 16:21:541250_VALID_OS_MACROS = (
1251 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081252 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541253 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441254 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121255 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541256 'OS_BSD',
1257 'OS_CAT', # For testing.
1258 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041259 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541260 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371261 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541262 'OS_IOS',
1263 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441264 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541265 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211266 'OS_NACL_NONSFI',
1267 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121268 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541269 'OS_OPENBSD',
1270 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371271 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541272 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541273 'OS_WIN',
1274)
1275
1276
Andrew Grieveb773bad2020-06-05 18:00:381277# These are not checked on the public chromium-presubmit trybot.
1278# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041279# checkouts.
agrievef32bcc72016-04-04 14:57:401280_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381281 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381282]
1283
1284
1285_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041286 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361287 'base/android/jni_generator/jni_generator.pydeps',
1288 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361289 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041290 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361291 'build/android/gyp/aar.pydeps',
1292 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271293 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361294 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381295 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361296 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021297 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111298 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361299 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361300 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361301 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111302 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041303 'build/android/gyp/create_app_bundle_apks.pydeps',
1304 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361305 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121306 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091307 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221308 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001309 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361310 'build/android/gyp/desugar.pydeps',
1311 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421312 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041313 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361315 'build/android/gyp/filter_zip.pydeps',
1316 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361317 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361318 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581319 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141321 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261322 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011323 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041324 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/merge_manifest.pydeps',
1327 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221328 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461330 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241331 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461333 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561334 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/incremental_install/generate_android_manifest.pydeps',
1336 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041337 'build/android/resource_sizes.pydeps',
1338 'build/android/test_runner.pydeps',
1339 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361340 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321342 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271343 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1344 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001345 'components/cronet/tools/generate_javadoc.pydeps',
1346 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381347 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001348 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381349 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041350 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181351 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041352 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421353 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1354 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131355 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061356 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221357 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401358]
1359
wnwenbdc444e2016-05-25 13:44:151360
agrievef32bcc72016-04-04 14:57:401361_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1362
1363
Eric Boren6fd2b932018-01-25 15:05:081364# Bypass the AUTHORS check for these accounts.
1365_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591366 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451367 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591368 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521369 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071370 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041371 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271372 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041373 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301374 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081375
1376
Daniel Bratell65b033262019-04-23 08:17:061377def _IsCPlusPlusFile(input_api, file_path):
1378 """Returns True if this file contains C++-like code (and not Python,
1379 Go, Java, MarkDown, ...)"""
1380
1381 ext = input_api.os_path.splitext(file_path)[1]
1382 # This list is compatible with CppChecker.IsCppFile but we should
1383 # consider adding ".c" to it. If we do that we can use this function
1384 # at more places in the code.
1385 return ext in (
1386 '.h',
1387 '.cc',
1388 '.cpp',
1389 '.m',
1390 '.mm',
1391 )
1392
1393def _IsCPlusPlusHeaderFile(input_api, file_path):
1394 return input_api.os_path.splitext(file_path)[1] == ".h"
1395
1396
1397def _IsJavaFile(input_api, file_path):
1398 return input_api.os_path.splitext(file_path)[1] == ".java"
1399
1400
1401def _IsProtoFile(input_api, file_path):
1402 return input_api.os_path.splitext(file_path)[1] == ".proto"
1403
Mohamed Heikal5e5b7922020-10-29 18:57:591404
1405def CheckNoUpstreamDepsOnClank(input_api, output_api):
1406 """Prevent additions of dependencies from the upstream repo on //clank."""
1407 # clank can depend on clank
1408 if input_api.change.RepositoryRoot().endswith('clank'):
1409 return []
1410 build_file_patterns = [
1411 r'(.+/)?BUILD\.gn',
1412 r'.+\.gni',
1413 ]
1414 excluded_files = [
1415 r'build[/\\]config[/\\]android[/\\]config\.gni'
1416 ]
1417 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1418
1419 error_message = 'Disallowed import on //clank in an upstream build file:'
1420
1421 def FilterFile(affected_file):
1422 return input_api.FilterSourceFile(
1423 affected_file,
1424 files_to_check=build_file_patterns,
1425 files_to_skip=excluded_files)
1426
1427 problems = []
1428 for f in input_api.AffectedSourceFiles(FilterFile):
1429 local_path = f.LocalPath()
1430 for line_number, line in f.ChangedContents():
1431 if (bad_pattern.search(line)):
1432 problems.append(
1433 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1434 if problems:
1435 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1436 else:
1437 return []
1438
1439
Saagar Sanghavifceeaae2020-08-12 16:40:361440def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191441 """Attempts to prevent use of functions intended only for testing in
1442 non-testing code. For now this is just a best-effort implementation
1443 that ignores header files and may have some false positives. A
1444 better implementation would probably need a proper C++ parser.
1445 """
1446 # We only scan .cc files and the like, as the declaration of
1447 # for-testing functions in header files are hard to distinguish from
1448 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491449 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191450
jochenc0d4808c2015-07-27 09:25:421451 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191452 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091453 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131454 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191455 exclusion_pattern = input_api.re.compile(
1456 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1457 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131458 # Avoid a false positive in this case, where the method name, the ::, and
1459 # the closing { are all on different lines due to line wrapping.
1460 # HelperClassForTesting::
1461 # HelperClassForTesting(
1462 # args)
1463 # : member(0) {}
1464 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191465
1466 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441467 files_to_skip = (_EXCLUDED_PATHS +
1468 _TEST_CODE_EXCLUDED_PATHS +
1469 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191470 return input_api.FilterSourceFile(
1471 affected_file,
James Cook24a504192020-07-23 00:08:441472 files_to_check=file_inclusion_pattern,
1473 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191474
1475 problems = []
1476 for f in input_api.AffectedSourceFiles(FilterFile):
1477 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131478 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241479 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031480 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461481 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131482 not exclusion_pattern.search(line) and
1483 not allowlist_pattern.search(line) and
1484 not in_method_defn):
[email protected]55459852011-08-10 15:17:191485 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031486 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131487 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191488
1489 if problems:
[email protected]f7051d52013-04-02 18:31:421490 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031491 else:
1492 return []
[email protected]55459852011-08-10 15:17:191493
1494
Saagar Sanghavifceeaae2020-08-12 16:40:361495def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231496 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591497 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231498 """
1499 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1500 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1501 name_pattern = r'ForTest(s|ing)?'
1502 # Describes an occurrence of "ForTest*" inside a // comment.
1503 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501504 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551505 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 # Catch calls.
1507 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1508 # Ignore definitions. (Comments are ignored separately.)
1509 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1510
1511 problems = []
1512 sources = lambda x: input_api.FilterSourceFile(
1513 x,
James Cook24a504192020-07-23 00:08:441514 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1515 + input_api.DEFAULT_FILES_TO_SKIP),
1516 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231517 )
1518 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1519 local_path = f.LocalPath()
1520 is_inside_javadoc = False
1521 for line_number, line in f.ChangedContents():
1522 if is_inside_javadoc and javadoc_end_re.search(line):
1523 is_inside_javadoc = False
1524 if not is_inside_javadoc and javadoc_start_re.search(line):
1525 is_inside_javadoc = True
1526 if is_inside_javadoc:
1527 continue
1528 if (inclusion_re.search(line) and
1529 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501530 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231531 not exclusion_re.search(line)):
1532 problems.append(
1533 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1534
1535 if problems:
1536 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1537 else:
1538 return []
1539
1540
Saagar Sanghavifceeaae2020-08-12 16:40:361541def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541542 """Checks to make sure no .h files include <iostream>."""
1543 files = []
1544 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1545 input_api.re.MULTILINE)
1546 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1547 if not f.LocalPath().endswith('.h'):
1548 continue
1549 contents = input_api.ReadFile(f)
1550 if pattern.search(contents):
1551 files.append(f)
1552
1553 if len(files):
yolandyandaabc6d2016-04-18 18:29:391554 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061555 'Do not #include <iostream> in header files, since it inserts static '
1556 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541557 '#include <ostream>. See http://crbug.com/94794',
1558 files) ]
1559 return []
1560
Danil Chapovalov3518f362018-08-11 16:13:431561def _CheckNoStrCatRedefines(input_api, output_api):
1562 """Checks no windows headers with StrCat redefined are included directly."""
1563 files = []
1564 pattern_deny = input_api.re.compile(
1565 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1566 input_api.re.MULTILINE)
1567 pattern_allow = input_api.re.compile(
1568 r'^#include\s"base/win/windows_defines.inc"',
1569 input_api.re.MULTILINE)
1570 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1571 contents = input_api.ReadFile(f)
1572 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1573 files.append(f.LocalPath())
1574
1575 if len(files):
1576 return [output_api.PresubmitError(
1577 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1578 'directly since they pollute code with StrCat macro. Instead, '
1579 'include matching header from base/win. See http://crbug.com/856536',
1580 files) ]
1581 return []
1582
[email protected]10689ca2011-09-02 02:31:541583
Saagar Sanghavifceeaae2020-08-12 16:40:361584def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521585 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181586 problems = []
1587 for f in input_api.AffectedFiles():
1588 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1589 continue
1590
1591 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041592 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181593 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1594
1595 if not problems:
1596 return []
1597 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1598 '\n'.join(problems))]
1599
Saagar Sanghavifceeaae2020-08-12 16:40:361600def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341601 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1602
1603 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1604 instead of DISABLED_. To filter false positives, reports are only generated
1605 if a corresponding MAYBE_ line exists.
1606 """
1607 problems = []
1608
1609 # The following two patterns are looked for in tandem - is a test labeled
1610 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1611 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1612 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1613
1614 # This is for the case that a test is disabled on all platforms.
1615 full_disable_pattern = input_api.re.compile(
1616 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1617 input_api.re.MULTILINE)
1618
Katie Df13948e2018-09-25 07:33:441619 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341620 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1621 continue
1622
1623 # Search for MABYE_, DISABLE_ pairs.
1624 disable_lines = {} # Maps of test name to line number.
1625 maybe_lines = {}
1626 for line_num, line in f.ChangedContents():
1627 disable_match = disable_pattern.search(line)
1628 if disable_match:
1629 disable_lines[disable_match.group(1)] = line_num
1630 maybe_match = maybe_pattern.search(line)
1631 if maybe_match:
1632 maybe_lines[maybe_match.group(1)] = line_num
1633
1634 # Search for DISABLE_ occurrences within a TEST() macro.
1635 disable_tests = set(disable_lines.keys())
1636 maybe_tests = set(maybe_lines.keys())
1637 for test in disable_tests.intersection(maybe_tests):
1638 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1639
1640 contents = input_api.ReadFile(f)
1641 full_disable_match = full_disable_pattern.search(contents)
1642 if full_disable_match:
1643 problems.append(' %s' % f.LocalPath())
1644
1645 if not problems:
1646 return []
1647 return [
1648 output_api.PresubmitPromptWarning(
1649 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1650 '\n'.join(problems))
1651 ]
1652
[email protected]72df4e782012-06-21 16:28:181653
Saagar Sanghavifceeaae2020-08-12 16:40:361654def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571655 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521656 errors = []
Hans Wennborg944479f2020-06-25 21:39:251657 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521658 input_api.re.MULTILINE)
1659 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1660 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1661 continue
1662 for lnum, line in f.ChangedContents():
1663 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171664 errors.append(output_api.PresubmitError(
1665 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571666 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171667 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521668 return errors
1669
1670
Weilun Shia487fad2020-10-28 00:10:341671# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1672# more reliable way. See
1673# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191674
wnwenbdc444e2016-05-25 13:44:151675
Saagar Sanghavifceeaae2020-08-12 16:40:361676def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391677 """Check that FlakyTest annotation is our own instead of the android one"""
1678 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1679 files = []
1680 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1681 if f.LocalPath().endswith('Test.java'):
1682 if pattern.search(input_api.ReadFile(f)):
1683 files.append(f)
1684 if len(files):
1685 return [output_api.PresubmitError(
1686 'Use org.chromium.base.test.util.FlakyTest instead of '
1687 'android.test.FlakyTest',
1688 files)]
1689 return []
mcasasb7440c282015-02-04 14:52:191690
wnwenbdc444e2016-05-25 13:44:151691
Saagar Sanghavifceeaae2020-08-12 16:40:361692def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221693 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271694 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221695 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201696 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571697 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341698 '/win/' in f.LocalPath() or
1699 'chrome_elf' in f.LocalPath() or
1700 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201701 continue
[email protected]8ea5d4b2011-09-13 21:49:221702
[email protected]a11dbe9b2012-08-07 01:32:581703 allowWString = False
[email protected]b5c24292011-11-28 14:38:201704 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581705 if 'presubmit: allow wstring' in line:
1706 allowWString = True
1707 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271708 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581709 allowWString = False
1710 else:
1711 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221712
[email protected]55463aa62011-10-12 00:48:271713 if not problems:
1714 return []
1715 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581716 ' If you are calling a cross-platform API that accepts a wstring, '
1717 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271718 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221719
1720
Saagar Sanghavifceeaae2020-08-12 16:40:361721def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441722 """Make sure .DEPS.git is never modified manually."""
1723 if any(f.LocalPath().endswith('.DEPS.git') for f in
1724 input_api.AffectedFiles()):
1725 return [output_api.PresubmitError(
1726 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1727 'automated system based on what\'s in DEPS and your changes will be\n'
1728 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501729 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1730 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441731 'for more information')]
1732 return []
1733
1734
Saagar Sanghavifceeaae2020-08-12 16:40:361735def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471736 """Checks that DEPS file deps are from allowed_hosts."""
1737 # Run only if DEPS file has been modified to annoy fewer bystanders.
1738 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1739 return []
1740 # Outsource work to gclient verify
1741 try:
John Budorickf20c0042019-04-25 23:23:401742 gclient_path = input_api.os_path.join(
1743 input_api.PresubmitLocalPath(),
1744 'third_party', 'depot_tools', 'gclient.py')
1745 input_api.subprocess.check_output(
1746 [input_api.python_executable, gclient_path, 'verify'],
1747 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471748 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201749 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471750 return [output_api.PresubmitError(
1751 'DEPS file must have only git dependencies.',
1752 long_text=error.output)]
1753
1754
Mario Sanchez Prada2472cab2019-09-18 10:58:311755def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1756 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591757 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311758
1759 Returns an string composed of the name of the file, the line number where the
1760 match has been found and the additional text passed as |message| in case the
1761 target type name matches the text inside the line passed as parameter.
1762 """
Peng Huang9c5949a02020-06-11 19:20:541763 result = []
1764
danakjd18e8892020-12-17 17:42:011765 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1766 return result
1767 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541768 return result
1769
Mario Sanchez Prada2472cab2019-09-18 10:58:311770 matched = False
1771 if type_name[0:1] == '/':
1772 regex = type_name[1:]
1773 if input_api.re.search(regex, line):
1774 matched = True
1775 elif type_name in line:
1776 matched = True
1777
Mario Sanchez Prada2472cab2019-09-18 10:58:311778 if matched:
1779 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1780 for message_line in message:
1781 result.append(' %s' % message_line)
1782
1783 return result
1784
1785
Saagar Sanghavifceeaae2020-08-12 16:40:361786def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591787 """Make sure that banned functions are not used."""
1788 warnings = []
1789 errors = []
1790
James Cook24a504192020-07-23 00:08:441791 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151792 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441793 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151794 if input_api.re.match(item, local_path):
1795 return True
1796 return False
1797
Peter K. Lee6c03ccff2019-07-15 14:40:051798 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541799 local_path = affected_file.LocalPath()
1800 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1801 return False
1802 basename = input_api.os_path.basename(local_path)
1803 if 'ios' in basename.split('_'):
1804 return True
1805 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1806 if sep and 'ios' in local_path.split(sep):
1807 return True
1808 return False
1809
wnwenbdc444e2016-05-25 13:44:151810 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311811 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1812 func_name, message)
1813 if problems:
wnwenbdc444e2016-05-25 13:44:151814 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311815 errors.extend(problems)
1816 else:
1817 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151818
Eric Stevensona9a980972017-09-23 00:04:411819 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1820 for f in input_api.AffectedFiles(file_filter=file_filter):
1821 for line_num, line in f.ChangedContents():
1822 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1823 CheckForMatch(f, line_num, line, func_name, message, error)
1824
[email protected]127f18ec2012-06-16 05:05:591825 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1826 for f in input_api.AffectedFiles(file_filter=file_filter):
1827 for line_num, line in f.ChangedContents():
1828 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151829 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591830
Peter K. Lee6c03ccff2019-07-15 14:40:051831 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541832 for line_num, line in f.ChangedContents():
1833 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1834 CheckForMatch(f, line_num, line, func_name, message, error)
1835
Peter K. Lee6c03ccff2019-07-15 14:40:051836 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1837 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1838 for line_num, line in f.ChangedContents():
1839 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1840 CheckForMatch(f, line_num, line, func_name, message, error)
1841
[email protected]127f18ec2012-06-16 05:05:591842 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1843 for f in input_api.AffectedFiles(file_filter=file_filter):
1844 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491845 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441846 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491847 continue
wnwenbdc444e2016-05-25 13:44:151848 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591849
1850 result = []
1851 if (warnings):
1852 result.append(output_api.PresubmitPromptWarning(
1853 'Banned functions were used.\n' + '\n'.join(warnings)))
1854 if (errors):
1855 result.append(output_api.PresubmitError(
1856 'Banned functions were used.\n' + '\n'.join(errors)))
1857 return result
1858
1859
Michael Thiessen44457642020-02-06 00:24:151860def _CheckAndroidNoBannedImports(input_api, output_api):
1861 """Make sure that banned java imports are not used."""
1862 errors = []
1863
1864 def IsException(path, exceptions):
1865 for exception in exceptions:
1866 if (path.startswith(exception)):
1867 return True
1868 return False
1869
1870 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1871 for f in input_api.AffectedFiles(file_filter=file_filter):
1872 for line_num, line in f.ChangedContents():
1873 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1874 if IsException(f.LocalPath(), exceptions):
1875 continue;
1876 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1877 'import ' + import_name, message)
1878 if problems:
1879 errors.extend(problems)
1880 result = []
1881 if (errors):
1882 result.append(output_api.PresubmitError(
1883 'Banned imports were used.\n' + '\n'.join(errors)))
1884 return result
1885
1886
Saagar Sanghavifceeaae2020-08-12 16:40:361887def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311888 """Make sure that old Mojo types are not used."""
1889 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571890 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311891
Mario Sanchez Pradaaab91382019-12-19 08:57:091892 # For any path that is not an "ok" or an "error" path, a warning will be
1893 # raised if deprecated mojo types are found.
1894 ok_paths = ['components/arc']
1895 error_paths = ['third_party/blink', 'content']
1896
Mario Sanchez Prada2472cab2019-09-18 10:58:311897 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1898 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571899 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091900 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311901 continue
1902
1903 for line_num, line in f.ChangedContents():
1904 for func_name, message in _DEPRECATED_MOJO_TYPES:
1905 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1906 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571907
Mario Sanchez Prada2472cab2019-09-18 10:58:311908 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091909 # Raise errors inside |error_paths| and warnings everywhere else.
1910 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571911 errors.extend(problems)
1912 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311913 warnings.extend(problems)
1914
1915 result = []
1916 if (warnings):
1917 result.append(output_api.PresubmitPromptWarning(
1918 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571919 if (errors):
1920 result.append(output_api.PresubmitError(
1921 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311922 return result
1923
1924
Saagar Sanghavifceeaae2020-08-12 16:40:361925def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061926 """Make sure that banned functions are not used."""
1927 files = []
1928 pattern = input_api.re.compile(r'^#pragma\s+once',
1929 input_api.re.MULTILINE)
1930 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1931 if not f.LocalPath().endswith('.h'):
1932 continue
1933 contents = input_api.ReadFile(f)
1934 if pattern.search(contents):
1935 files.append(f)
1936
1937 if files:
1938 return [output_api.PresubmitError(
1939 'Do not use #pragma once in header files.\n'
1940 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1941 files)]
1942 return []
1943
[email protected]127f18ec2012-06-16 05:05:591944
Saagar Sanghavifceeaae2020-08-12 16:40:361945def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121946 """Checks to make sure we don't introduce use of foo ? true : false."""
1947 problems = []
1948 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1949 for f in input_api.AffectedFiles():
1950 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1951 continue
1952
1953 for line_num, line in f.ChangedContents():
1954 if pattern.match(line):
1955 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1956
1957 if not problems:
1958 return []
1959 return [output_api.PresubmitPromptWarning(
1960 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1961 '\n'.join(problems))]
1962
1963
Saagar Sanghavifceeaae2020-08-12 16:40:361964def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281965 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181966 change. Breaking - rules is an error, breaking ! rules is a
1967 warning.
1968 """
mohan.reddyf21db962014-10-16 12:26:471969 import sys
[email protected]55f9f382012-07-31 11:02:181970 # We need to wait until we have an input_api object and use this
1971 # roundabout construct to import checkdeps because this file is
1972 # eval-ed and thus doesn't have __file__.
1973 original_sys_path = sys.path
1974 try:
1975 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471976 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181977 import checkdeps
[email protected]55f9f382012-07-31 11:02:181978 from rules import Rule
1979 finally:
1980 # Restore sys.path to what it was before.
1981 sys.path = original_sys_path
1982
1983 added_includes = []
rhalavati08acd232017-04-03 07:23:281984 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241985 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181986 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061987 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501988 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081989 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061990 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501991 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081992 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061993 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501994 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081995 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181996
[email protected]26385172013-05-09 23:11:351997 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181998
1999 error_descriptions = []
2000 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282001 error_subjects = set()
2002 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362003
[email protected]55f9f382012-07-31 11:02:182004 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2005 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082006 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182007 description_with_path = '%s\n %s' % (path, rule_description)
2008 if rule_type == Rule.DISALLOW:
2009 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282010 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182011 else:
2012 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282013 warning_subjects.add("#includes")
2014
2015 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2016 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082017 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282018 description_with_path = '%s\n %s' % (path, rule_description)
2019 if rule_type == Rule.DISALLOW:
2020 error_descriptions.append(description_with_path)
2021 error_subjects.add("imports")
2022 else:
2023 warning_descriptions.append(description_with_path)
2024 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182025
Jinsuk Kim5a092672017-10-24 22:42:242026 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022027 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082028 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242029 description_with_path = '%s\n %s' % (path, rule_description)
2030 if rule_type == Rule.DISALLOW:
2031 error_descriptions.append(description_with_path)
2032 error_subjects.add("imports")
2033 else:
2034 warning_descriptions.append(description_with_path)
2035 warning_subjects.add("imports")
2036
[email protected]55f9f382012-07-31 11:02:182037 results = []
2038 if error_descriptions:
2039 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282040 'You added one or more %s that violate checkdeps rules.'
2041 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182042 error_descriptions))
2043 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422044 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282045 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182046 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282047 '%s? See relevant DEPS file(s) for details and contacts.' %
2048 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182049 warning_descriptions))
2050 return results
2051
2052
Saagar Sanghavifceeaae2020-08-12 16:40:362053def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222054 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152055 if input_api.platform == 'win32':
2056 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292057 checkperms_tool = input_api.os_path.join(
2058 input_api.PresubmitLocalPath(),
2059 'tools', 'checkperms', 'checkperms.py')
2060 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472061 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392062 with input_api.CreateTemporaryFile() as file_list:
2063 for f in input_api.AffectedFiles():
2064 # checkperms.py file/directory arguments must be relative to the
2065 # repository.
2066 file_list.write(f.LocalPath() + '\n')
2067 file_list.close()
2068 args += ['--file-list', file_list.name]
2069 try:
2070 input_api.subprocess.check_output(args)
2071 return []
2072 except input_api.subprocess.CalledProcessError as error:
2073 return [output_api.PresubmitError(
2074 'checkperms.py failed:',
2075 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222076
2077
Saagar Sanghavifceeaae2020-08-12 16:40:362078def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492079 """Makes sure we don't include ui/aura/window_property.h
2080 in header files.
2081 """
2082 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2083 errors = []
2084 for f in input_api.AffectedFiles():
2085 if not f.LocalPath().endswith('.h'):
2086 continue
2087 for line_num, line in f.ChangedContents():
2088 if pattern.match(line):
2089 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2090
2091 results = []
2092 if errors:
2093 results.append(output_api.PresubmitError(
2094 'Header files should not include ui/aura/window_property.h', errors))
2095 return results
2096
2097
[email protected]70ca77752012-11-20 03:45:032098def _CheckForVersionControlConflictsInFile(input_api, f):
2099 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2100 errors = []
2101 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162102 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232103 # First-level headers in markdown look a lot like version control
2104 # conflict markers. http://daringfireball.net/projects/markdown/basics
2105 continue
[email protected]70ca77752012-11-20 03:45:032106 if pattern.match(line):
2107 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2108 return errors
2109
2110
Saagar Sanghavifceeaae2020-08-12 16:40:362111def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032112 """Usually this is not intentional and will cause a compile failure."""
2113 errors = []
2114 for f in input_api.AffectedFiles():
2115 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2116
2117 results = []
2118 if errors:
2119 results.append(output_api.PresubmitError(
2120 'Version control conflict markers found, please resolve.', errors))
2121 return results
2122
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202123
Saagar Sanghavifceeaae2020-08-12 16:40:362124def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162125 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2126 errors = []
2127 for f in input_api.AffectedFiles():
2128 for line_num, line in f.ChangedContents():
2129 if pattern.search(line):
2130 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2131
2132 results = []
2133 if errors:
2134 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502135 'Found Google support URL addressed by answer number. Please replace '
2136 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162137 return results
2138
[email protected]70ca77752012-11-20 03:45:032139
Saagar Sanghavifceeaae2020-08-12 16:40:362140def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442141 def FilterFile(affected_file):
2142 """Filter function for use with input_api.AffectedSourceFiles,
2143 below. This filters out everything except non-test files from
2144 top-level directories that generally speaking should not hard-code
2145 service URLs (e.g. src/android_webview/, src/content/ and others).
2146 """
2147 return input_api.FilterSourceFile(
2148 affected_file,
James Cook24a504192020-07-23 00:08:442149 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2150 files_to_skip=(_EXCLUDED_PATHS +
2151 _TEST_CODE_EXCLUDED_PATHS +
2152 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442153
reillyi38965732015-11-16 18:27:332154 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2155 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462156 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2157 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442158 problems = [] # items are (filename, line_number, line)
2159 for f in input_api.AffectedSourceFiles(FilterFile):
2160 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462161 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442162 problems.append((f.LocalPath(), line_num, line))
2163
2164 if problems:
[email protected]f7051d52013-04-02 18:31:422165 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442166 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582167 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442168 [' %s:%d: %s' % (
2169 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032170 else:
2171 return []
[email protected]06e6d0ff2012-12-11 01:36:442172
2173
Saagar Sanghavifceeaae2020-08-12 16:40:362174def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292175 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2176 def FileFilter(affected_file):
2177 """Includes directories known to be Chrome OS only."""
2178 return input_api.FilterSourceFile(
2179 affected_file,
James Cook24a504192020-07-23 00:08:442180 files_to_check=('^ash/',
2181 '^chromeos/', # Top-level src/chromeos.
2182 '/chromeos/', # Any path component.
2183 '^components/arc',
2184 '^components/exo'),
2185 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292186
2187 prefs = []
2188 priority_prefs = []
2189 for f in input_api.AffectedFiles(file_filter=FileFilter):
2190 for line_num, line in f.ChangedContents():
2191 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2192 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2193 prefs.append(' %s' % line)
2194 if input_api.re.search(
2195 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2196 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2197 priority_prefs.append(' %s' % line)
2198
2199 results = []
2200 if (prefs):
2201 results.append(output_api.PresubmitPromptWarning(
2202 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2203 'by browser sync settings. If these prefs should be controlled by OS '
2204 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2205 if (priority_prefs):
2206 results.append(output_api.PresubmitPromptWarning(
2207 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2208 'controlled by browser sync settings. If these prefs should be '
2209 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2210 'instead.\n' + '\n'.join(prefs)))
2211 return results
2212
2213
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492214# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362215def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272216 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312217 The native_client_sdk directory is excluded because it has auto-generated PNG
2218 files for documentation.
[email protected]d2530012013-01-25 16:39:272219 """
[email protected]d2530012013-01-25 16:39:272220 errors = []
James Cook24a504192020-07-23 00:08:442221 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2222 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312223 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442224 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312225 for f in input_api.AffectedFiles(include_deletes=False,
2226 file_filter=file_filter):
2227 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272228
2229 results = []
2230 if errors:
2231 results.append(output_api.PresubmitError(
2232 'The name of PNG files should not have abbreviations. \n'
2233 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2234 'Contact [email protected] if you have questions.', errors))
2235 return results
2236
2237
Daniel Cheng4dcdb6b2017-04-13 08:30:172238def _ExtractAddRulesFromParsedDeps(parsed_deps):
2239 """Extract the rules that add dependencies from a parsed DEPS file.
2240
2241 Args:
2242 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2243 add_rules = set()
2244 add_rules.update([
2245 rule[1:] for rule in parsed_deps.get('include_rules', [])
2246 if rule.startswith('+') or rule.startswith('!')
2247 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502248 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172249 {}).iteritems():
2250 add_rules.update([
2251 rule[1:] for rule in rules
2252 if rule.startswith('+') or rule.startswith('!')
2253 ])
2254 return add_rules
2255
2256
2257def _ParseDeps(contents):
2258 """Simple helper for parsing DEPS files."""
2259 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172260 class _VarImpl:
2261
2262 def __init__(self, local_scope):
2263 self._local_scope = local_scope
2264
2265 def Lookup(self, var_name):
2266 """Implements the Var syntax."""
2267 try:
2268 return self._local_scope['vars'][var_name]
2269 except KeyError:
2270 raise Exception('Var is not defined: %s' % var_name)
2271
2272 local_scope = {}
2273 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172274 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592275 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172276 }
2277 exec contents in global_scope, local_scope
2278 return local_scope
2279
2280
2281def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592282 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412283 a set of DEPS entries that we should look up.
2284
2285 For a directory (rather than a specific filename) we fake a path to
2286 a specific filename by adding /DEPS. This is chosen as a file that
2287 will seldom or never be subject to per-file include_rules.
2288 """
[email protected]2b438d62013-11-14 17:54:142289 # We ignore deps entries on auto-generated directories.
2290 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082291
Daniel Cheng4dcdb6b2017-04-13 08:30:172292 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2293 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2294
2295 added_deps = new_deps.difference(old_deps)
2296
[email protected]2b438d62013-11-14 17:54:142297 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172298 for added_dep in added_deps:
2299 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2300 continue
2301 # Assume that a rule that ends in .h is a rule for a specific file.
2302 if added_dep.endswith('.h'):
2303 results.add(added_dep)
2304 else:
2305 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082306 return results
2307
2308
Saagar Sanghavifceeaae2020-08-12 16:40:362309def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552310 """When a dependency prefixed with + is added to a DEPS file, we
2311 want to make sure that the change is reviewed by an OWNER of the
2312 target file or directory, to avoid layering violations from being
2313 introduced. This check verifies that this happens.
2314 """
Edward Lesmes6fba51082021-01-20 04:20:232315 if input_api.change.issue:
2316 # Skip OWNERS check when Bot-Commit label is approved. This label is
2317 # intended for commits made by trusted bots that don't require review nor
2318 # owners approval.
2319 if input_api.gerrit.IsBotCommitApproved(input_api.change.issue):
2320 return []
2321 # Skip OWNERS check when Owners-Override label is approved. This is intended
2322 # for global owners, trusted bots, and on-call sheriffs. Review is still
2323 # required for these changes.
2324 if input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue):
2325 return []
2326
Daniel Cheng4dcdb6b2017-04-13 08:30:172327 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242328
2329 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492330 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242331 for f in input_api.AffectedFiles(include_deletes=False,
2332 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552333 filename = input_api.os_path.basename(f.LocalPath())
2334 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172335 virtual_depended_on_files.update(_CalculateAddedDeps(
2336 input_api.os_path,
2337 '\n'.join(f.OldContents()),
2338 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552339
[email protected]e871964c2013-05-13 14:14:552340 if not virtual_depended_on_files:
2341 return []
2342
2343 if input_api.is_committing:
2344 if input_api.tbr:
2345 return [output_api.PresubmitNotifyResult(
2346 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272347 if input_api.dry_run:
2348 return [output_api.PresubmitNotifyResult(
2349 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552350 if not input_api.change.issue:
2351 return [output_api.PresubmitError(
2352 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402353 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552354 output = output_api.PresubmitError
2355 else:
2356 output = output_api.PresubmitNotifyResult
2357
tandriied3b7e12016-05-12 14:38:502358 owner_email, reviewers = (
2359 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2360 input_api,
Edward Lesmesa3846442021-02-08 20:20:032361 None,
tandriied3b7e12016-05-12 14:38:502362 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552363
2364 owner_email = owner_email or input_api.change.author_email
2365
Edward Lesmesa3846442021-02-08 20:20:032366 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2367 virtual_depended_on_files, reviewers.union([owner_email]), [])
2368 missing_files = [
2369 f for f in virtual_depended_on_files
2370 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412371
2372 # We strip the /DEPS part that was added by
2373 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2374 # directory.
2375 def StripDeps(path):
2376 start_deps = path.rfind('/DEPS')
2377 if start_deps != -1:
2378 return path[:start_deps]
2379 else:
2380 return path
2381 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552382 for path in missing_files]
2383
2384 if unapproved_dependencies:
2385 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152386 output('You need LGTM from owners of depends-on paths in DEPS that were '
2387 'modified in this CL:\n %s' %
2388 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032389 suggested_owners = input_api.owners_client.SuggestOwners(
2390 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152391 output_list.append(output(
2392 'Suggested missing target path OWNERS:\n %s' %
2393 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552394 return output_list
2395
2396 return []
2397
2398
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492399# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362400def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492401 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442402 files_to_skip = (_EXCLUDED_PATHS +
2403 _TEST_CODE_EXCLUDED_PATHS +
2404 input_api.DEFAULT_FILES_TO_SKIP +
2405 (r"^base[\\/]logging\.h$",
2406 r"^base[\\/]logging\.cc$",
2407 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2408 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2409 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2410 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2411 r"startup_browser_creator\.cc$",
2412 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2413 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2414 r"diagnostics_writer\.cc$",
2415 r"^chrome[\\/]chrome_cleaner[\\/].*",
2416 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2417 r"dll_hash_main\.cc$",
2418 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2419 r"^chromecast[\\/]",
2420 r"^cloud_print[\\/]",
2421 r"^components[\\/]browser_watcher[\\/]"
2422 r"dump_stability_report_main_win.cc$",
2423 r"^components[\\/]media_control[\\/]renderer[\\/]"
2424 r"media_playback_options\.cc$",
2425 r"^components[\\/]zucchini[\\/].*",
2426 # TODO(peter): Remove exception. https://crbug.com/534537
2427 r"^content[\\/]browser[\\/]notifications[\\/]"
2428 r"notification_event_dispatcher_impl\.cc$",
2429 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2430 r"gl_helper_benchmark\.cc$",
2431 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2432 r"^courgette[\\/]courgette_tool\.cc$",
2433 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2434 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2435 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2436 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2437 r"^ipc[\\/]ipc_logging\.cc$",
2438 r"^native_client_sdk[\\/]",
2439 r"^remoting[\\/]base[\\/]logging\.h$",
2440 r"^remoting[\\/]host[\\/].*",
2441 r"^sandbox[\\/]linux[\\/].*",
2442 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2443 r"dump_file_system.cc$",
2444 r"^tools[\\/]",
2445 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2446 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2447 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2448 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2449 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402450 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442451 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402452
thomasanderson625d3932017-03-29 07:16:582453 log_info = set([])
2454 printf = set([])
[email protected]85218562013-11-22 07:41:402455
2456 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582457 for _, line in f.ChangedContents():
2458 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2459 log_info.add(f.LocalPath())
2460 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2461 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372462
thomasanderson625d3932017-03-29 07:16:582463 if input_api.re.search(r"\bprintf\(", line):
2464 printf.add(f.LocalPath())
2465 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2466 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402467
2468 if log_info:
2469 return [output_api.PresubmitError(
2470 'These files spam the console log with LOG(INFO):',
2471 items=log_info)]
2472 if printf:
2473 return [output_api.PresubmitError(
2474 'These files spam the console log with printf/fprintf:',
2475 items=printf)]
2476 return []
2477
2478
Saagar Sanghavifceeaae2020-08-12 16:40:362479def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162480 """These types are all expected to hold locks while in scope and
2481 so should never be anonymous (which causes them to be immediately
2482 destroyed)."""
2483 they_who_must_be_named = [
2484 'base::AutoLock',
2485 'base::AutoReset',
2486 'base::AutoUnlock',
2487 'SkAutoAlphaRestore',
2488 'SkAutoBitmapShaderInstall',
2489 'SkAutoBlitterChoose',
2490 'SkAutoBounderCommit',
2491 'SkAutoCallProc',
2492 'SkAutoCanvasRestore',
2493 'SkAutoCommentBlock',
2494 'SkAutoDescriptor',
2495 'SkAutoDisableDirectionCheck',
2496 'SkAutoDisableOvalCheck',
2497 'SkAutoFree',
2498 'SkAutoGlyphCache',
2499 'SkAutoHDC',
2500 'SkAutoLockColors',
2501 'SkAutoLockPixels',
2502 'SkAutoMalloc',
2503 'SkAutoMaskFreeImage',
2504 'SkAutoMutexAcquire',
2505 'SkAutoPathBoundsUpdate',
2506 'SkAutoPDFRelease',
2507 'SkAutoRasterClipValidate',
2508 'SkAutoRef',
2509 'SkAutoTime',
2510 'SkAutoTrace',
2511 'SkAutoUnref',
2512 ]
2513 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2514 # bad: base::AutoLock(lock.get());
2515 # not bad: base::AutoLock lock(lock.get());
2516 bad_pattern = input_api.re.compile(anonymous)
2517 # good: new base::AutoLock(lock.get())
2518 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2519 errors = []
2520
2521 for f in input_api.AffectedFiles():
2522 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2523 continue
2524 for linenum, line in f.ChangedContents():
2525 if bad_pattern.search(line) and not good_pattern.search(line):
2526 errors.append('%s:%d' % (f.LocalPath(), linenum))
2527
2528 if errors:
2529 return [output_api.PresubmitError(
2530 'These lines create anonymous variables that need to be named:',
2531 items=errors)]
2532 return []
2533
2534
Saagar Sanghavifceeaae2020-08-12 16:40:362535def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532536 # Returns whether |template_str| is of the form <T, U...> for some types T
2537 # and U. Assumes that |template_str| is already in the form <...>.
2538 def HasMoreThanOneArg(template_str):
2539 # Level of <...> nesting.
2540 nesting = 0
2541 for c in template_str:
2542 if c == '<':
2543 nesting += 1
2544 elif c == '>':
2545 nesting -= 1
2546 elif c == ',' and nesting == 1:
2547 return True
2548 return False
2549
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492550 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102551 sources = lambda affected_file: input_api.FilterSourceFile(
2552 affected_file,
James Cook24a504192020-07-23 00:08:442553 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2554 input_api.DEFAULT_FILES_TO_SKIP),
2555 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552556
2557 # Pattern to capture a single "<...>" block of template arguments. It can
2558 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2559 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2560 # latter would likely require counting that < and > match, which is not
2561 # expressible in regular languages. Should the need arise, one can introduce
2562 # limited counting (matching up to a total number of nesting depth), which
2563 # should cover all practical cases for already a low nesting limit.
2564 template_arg_pattern = (
2565 r'<[^>]*' # Opening block of <.
2566 r'>([^<]*>)?') # Closing block of >.
2567 # Prefix expressing that whatever follows is not already inside a <...>
2568 # block.
2569 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102570 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552571 not_inside_template_arg_pattern
2572 + r'\bstd::unique_ptr'
2573 + template_arg_pattern
2574 + r'\(\)')
2575
2576 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2577 template_arg_no_array_pattern = (
2578 r'<[^>]*[^]]' # Opening block of <.
2579 r'>([^(<]*[^]]>)?') # Closing block of >.
2580 # Prefix saying that what follows is the start of an expression.
2581 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2582 # Suffix saying that what follows are call parentheses with a non-empty list
2583 # of arguments.
2584 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532585 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552586 return_construct_pattern = input_api.re.compile(
2587 start_of_expr_pattern
2588 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532589 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552590 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532591 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552592 + nonempty_arg_list_pattern)
2593
Vaclav Brozek851d9602018-04-04 16:13:052594 problems_constructor = []
2595 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102596 for f in input_api.AffectedSourceFiles(sources):
2597 for line_number, line in f.ChangedContents():
2598 # Disallow:
2599 # return std::unique_ptr<T>(foo);
2600 # bar = std::unique_ptr<T>(foo);
2601 # But allow:
2602 # return std::unique_ptr<T[]>(foo);
2603 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532604 # And also allow cases when the second template argument is present. Those
2605 # cases cannot be handled by std::make_unique:
2606 # return std::unique_ptr<T, U>(foo);
2607 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052608 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532609 return_construct_result = return_construct_pattern.search(line)
2610 if return_construct_result and not HasMoreThanOneArg(
2611 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052612 problems_constructor.append(
2613 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102614 # Disallow:
2615 # std::unique_ptr<T>()
2616 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052617 problems_nullptr.append(
2618 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2619
2620 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162621 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052622 errors.append(output_api.PresubmitError(
2623 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162624 problems_nullptr))
2625 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052626 errors.append(output_api.PresubmitError(
2627 'The following files use explicit std::unique_ptr constructor.'
2628 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162629 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102630 return errors
2631
2632
Saagar Sanghavifceeaae2020-08-12 16:40:362633def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082634 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522635 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082636 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522637 # If actions.xml is already included in the changelist, the PRESUBMIT
2638 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082639 return []
2640
[email protected]999261d2014-03-03 20:08:082641 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2642 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522643 current_actions = None
[email protected]999261d2014-03-03 20:08:082644 for f in input_api.AffectedFiles(file_filter=file_filter):
2645 for line_num, line in f.ChangedContents():
2646 match = input_api.re.search(action_re, line)
2647 if match:
[email protected]2f92dec2014-03-07 19:21:522648 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2649 # loaded only once.
2650 if not current_actions:
2651 with open('tools/metrics/actions/actions.xml') as actions_f:
2652 current_actions = actions_f.read()
2653 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082654 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522655 action = 'name="{0}"'.format(action_name)
2656 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082657 return [output_api.PresubmitPromptWarning(
2658 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522659 'tools/metrics/actions/actions.xml. Please run '
2660 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082661 % (f.LocalPath(), line_num, action_name))]
2662 return []
2663
2664
Daniel Cheng13ca61a882017-08-25 15:11:252665def _ImportJSONCommentEater(input_api):
2666 import sys
2667 sys.path = sys.path + [input_api.os_path.join(
2668 input_api.PresubmitLocalPath(),
2669 'tools', 'json_comment_eater')]
2670 import json_comment_eater
2671 return json_comment_eater
2672
2673
[email protected]99171a92014-06-03 08:44:472674def _GetJSONParseError(input_api, filename, eat_comments=True):
2675 try:
2676 contents = input_api.ReadFile(filename)
2677 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252678 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132679 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472680
2681 input_api.json.loads(contents)
2682 except ValueError as e:
2683 return e
2684 return None
2685
2686
2687def _GetIDLParseError(input_api, filename):
2688 try:
2689 contents = input_api.ReadFile(filename)
2690 idl_schema = input_api.os_path.join(
2691 input_api.PresubmitLocalPath(),
2692 'tools', 'json_schema_compiler', 'idl_schema.py')
2693 process = input_api.subprocess.Popen(
2694 [input_api.python_executable, idl_schema],
2695 stdin=input_api.subprocess.PIPE,
2696 stdout=input_api.subprocess.PIPE,
2697 stderr=input_api.subprocess.PIPE,
2698 universal_newlines=True)
2699 (_, error) = process.communicate(input=contents)
2700 return error or None
2701 except ValueError as e:
2702 return e
2703
2704
Saagar Sanghavifceeaae2020-08-12 16:40:362705def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472706 """Check that IDL and JSON files do not contain syntax errors."""
2707 actions = {
2708 '.idl': _GetIDLParseError,
2709 '.json': _GetJSONParseError,
2710 }
[email protected]99171a92014-06-03 08:44:472711 # Most JSON files are preprocessed and support comments, but these do not.
2712 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042713 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472714 ]
2715 # Only run IDL checker on files in these directories.
2716 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042717 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2718 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472719 ]
2720
2721 def get_action(affected_file):
2722 filename = affected_file.LocalPath()
2723 return actions.get(input_api.os_path.splitext(filename)[1])
2724
[email protected]99171a92014-06-03 08:44:472725 def FilterFile(affected_file):
2726 action = get_action(affected_file)
2727 if not action:
2728 return False
2729 path = affected_file.LocalPath()
2730
Erik Staab2dd72b12020-04-16 15:03:402731 if _MatchesFile(input_api,
2732 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2733 path):
[email protected]99171a92014-06-03 08:44:472734 return False
2735
2736 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162737 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472738 return False
2739 return True
2740
2741 results = []
2742 for affected_file in input_api.AffectedFiles(
2743 file_filter=FilterFile, include_deletes=False):
2744 action = get_action(affected_file)
2745 kwargs = {}
2746 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162747 _MatchesFile(input_api, json_no_comments_patterns,
2748 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472749 kwargs['eat_comments'] = False
2750 parse_error = action(input_api,
2751 affected_file.AbsoluteLocalPath(),
2752 **kwargs)
2753 if parse_error:
2754 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2755 (affected_file.LocalPath(), parse_error)))
2756 return results
2757
2758
Saagar Sanghavifceeaae2020-08-12 16:40:362759def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492760 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472761 import sys
[email protected]760deea2013-12-10 19:33:492762 original_sys_path = sys.path
2763 try:
2764 sys.path = sys.path + [input_api.os_path.join(
2765 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2766 import checkstyle
2767 finally:
2768 # Restore sys.path to what it was before.
2769 sys.path = original_sys_path
2770
2771 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092772 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442773 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492774
2775
Saagar Sanghavifceeaae2020-08-12 16:40:362776def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002777 """Checks to make sure devil is initialized correctly in python scripts."""
2778 script_common_initialize_pattern = input_api.re.compile(
2779 r'script_common\.InitializeEnvironment\(')
2780 devil_env_config_initialize = input_api.re.compile(
2781 r'devil_env\.config\.Initialize\(')
2782
2783 errors = []
2784
2785 sources = lambda affected_file: input_api.FilterSourceFile(
2786 affected_file,
James Cook24a504192020-07-23 00:08:442787 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2788 (r'^build[\\/]android[\\/]devil_chromium\.py',
2789 r'^third_party[\\/].*',)),
2790 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002791
2792 for f in input_api.AffectedSourceFiles(sources):
2793 for line_num, line in f.ChangedContents():
2794 if (script_common_initialize_pattern.search(line) or
2795 devil_env_config_initialize.search(line)):
2796 errors.append("%s:%d" % (f.LocalPath(), line_num))
2797
2798 results = []
2799
2800 if errors:
2801 results.append(output_api.PresubmitError(
2802 'Devil initialization should always be done using '
2803 'devil_chromium.Initialize() in the chromium project, to use better '
2804 'defaults for dependencies (ex. up-to-date version of adb).',
2805 errors))
2806
2807 return results
2808
2809
Sean Kau46e29bc2017-08-28 16:31:162810def _MatchesFile(input_api, patterns, path):
2811 for pattern in patterns:
2812 if input_api.re.search(pattern, path):
2813 return True
2814 return False
2815
2816
Daniel Cheng7052cdf2017-11-21 19:23:292817def _GetOwnersFilesToCheckForIpcOwners(input_api):
2818 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172819
Daniel Cheng7052cdf2017-11-21 19:23:292820 Returns:
2821 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2822 contain to cover IPC-related files with noparent reviewer rules.
2823 """
2824 # Whether or not a file affects IPC is (mostly) determined by a simple list
2825 # of filename patterns.
dchenge07de812016-06-20 19:27:172826 file_patterns = [
palmerb19a0932017-01-24 04:00:312827 # Legacy IPC:
dchenge07de812016-06-20 19:27:172828 '*_messages.cc',
2829 '*_messages*.h',
2830 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312831 # Mojo IPC:
dchenge07de812016-06-20 19:27:172832 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472833 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172834 '*_struct_traits*.*',
2835 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312836 '*.typemap',
2837 # Android native IPC:
2838 '*.aidl',
2839 # Blink uses a different file naming convention:
2840 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472841 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172842 '*StructTraits*.*',
2843 '*TypeConverter*.*',
2844 ]
2845
scottmg7a6ed5ba2016-11-04 18:22:042846 # These third_party directories do not contain IPCs, but contain files
2847 # matching the above patterns, which trigger false positives.
2848 exclude_paths = [
2849 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162850 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232851 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292852 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542853 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162854 # These files are just used to communicate between class loaders running
2855 # in the same process.
2856 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572857 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2858
scottmg7a6ed5ba2016-11-04 18:22:042859 ]
2860
dchenge07de812016-06-20 19:27:172861 # Dictionary mapping an OWNERS file path to Patterns.
2862 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2863 # rules ) to a PatternEntry.
2864 # PatternEntry is a dictionary with two keys:
2865 # - 'files': the files that are matched by this pattern
2866 # - 'rules': the per-file rules needed for this pattern
2867 # For example, if we expect OWNERS file to contain rules for *.mojom and
2868 # *_struct_traits*.*, Patterns might look like this:
2869 # {
2870 # '*.mojom': {
2871 # 'files': ...,
2872 # 'rules': [
2873 # 'per-file *.mojom=set noparent',
2874 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2875 # ],
2876 # },
2877 # '*_struct_traits*.*': {
2878 # 'files': ...,
2879 # 'rules': [
2880 # 'per-file *_struct_traits*.*=set noparent',
2881 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2882 # ],
2883 # },
2884 # }
2885 to_check = {}
2886
Daniel Cheng13ca61a882017-08-25 15:11:252887 def AddPatternToCheck(input_file, pattern):
2888 owners_file = input_api.os_path.join(
2889 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2890 if owners_file not in to_check:
2891 to_check[owners_file] = {}
2892 if pattern not in to_check[owners_file]:
2893 to_check[owners_file][pattern] = {
2894 'files': [],
2895 'rules': [
2896 'per-file %s=set noparent' % pattern,
2897 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2898 ]
2899 }
Vaclav Brozekd5de76a2018-03-17 07:57:502900 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252901
dchenge07de812016-06-20 19:27:172902 # Iterate through the affected files to see what we actually need to check
2903 # for. We should only nag patch authors about per-file rules if a file in that
2904 # directory would match that pattern. If a directory only contains *.mojom
2905 # files and no *_messages*.h files, we should only nag about rules for
2906 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252907 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262908 # Manifest files don't have a strong naming convention. Instead, try to find
2909 # affected .cc and .h files which look like they contain a manifest
2910 # definition.
2911 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2912 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2913 if (manifest_pattern.search(f.LocalPath()) and not
2914 test_manifest_pattern.search(f.LocalPath())):
2915 # We expect all actual service manifest files to contain at least one
2916 # qualified reference to service_manager::Manifest.
2917 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252918 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172919 for pattern in file_patterns:
2920 if input_api.fnmatch.fnmatch(
2921 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042922 skip = False
2923 for exclude in exclude_paths:
2924 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2925 skip = True
2926 break
2927 if skip:
2928 continue
Daniel Cheng13ca61a882017-08-25 15:11:252929 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172930 break
2931
Daniel Cheng7052cdf2017-11-21 19:23:292932 return to_check
2933
2934
Wez17c66962020-04-29 15:26:032935def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2936 """Adds OWNERS files to check for correct Fuchsia security owners."""
2937
2938 file_patterns = [
2939 # Component specifications.
2940 '*.cml', # Component Framework v2.
2941 '*.cmx', # Component Framework v1.
2942
2943 # Fuchsia IDL protocol specifications.
2944 '*.fidl',
2945 ]
2946
Joshua Peraza1ca6d392020-12-08 00:14:092947 # Don't check for owners files for changes in these directories.
2948 exclude_paths = [
2949 'third_party/crashpad/*',
2950 ]
2951
Wez17c66962020-04-29 15:26:032952 def AddPatternToCheck(input_file, pattern):
2953 owners_file = input_api.os_path.join(
2954 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2955 if owners_file not in to_check:
2956 to_check[owners_file] = {}
2957 if pattern not in to_check[owners_file]:
2958 to_check[owners_file][pattern] = {
2959 'files': [],
2960 'rules': [
2961 'per-file %s=set noparent' % pattern,
2962 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2963 ]
2964 }
2965 to_check[owners_file][pattern]['files'].append(input_file)
2966
2967 # Iterate through the affected files to see what we actually need to check
2968 # for. We should only nag patch authors about per-file rules if a file in that
2969 # directory would match that pattern.
2970 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092971 skip = False
2972 for exclude in exclude_paths:
2973 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2974 skip = True
2975 if skip:
2976 continue
2977
Wez17c66962020-04-29 15:26:032978 for pattern in file_patterns:
2979 if input_api.fnmatch.fnmatch(
2980 input_api.os_path.basename(f.LocalPath()), pattern):
2981 AddPatternToCheck(f, pattern)
2982 break
2983
2984 return to_check
2985
2986
Saagar Sanghavifceeaae2020-08-12 16:40:362987def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292988 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2989 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032990 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292991
2992 if to_check:
2993 # If there are any OWNERS files to check, there are IPC-related changes in
2994 # this CL. Auto-CC the review list.
2995 output_api.AppendCC('[email protected]')
2996
2997 # Go through the OWNERS files to check, filtering out rules that are already
2998 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172999 for owners_file, patterns in to_check.iteritems():
3000 try:
3001 with file(owners_file) as f:
3002 lines = set(f.read().splitlines())
3003 for entry in patterns.itervalues():
3004 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3005 ]
3006 except IOError:
3007 # No OWNERS file, so all the rules are definitely missing.
3008 continue
3009
3010 # All the remaining lines weren't found in OWNERS files, so emit an error.
3011 errors = []
3012 for owners_file, patterns in to_check.iteritems():
3013 missing_lines = []
3014 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503015 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173016 missing_lines.extend(entry['rules'])
3017 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3018 if missing_lines:
3019 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053020 'Because of the presence of files:\n%s\n\n'
3021 '%s needs the following %d lines added:\n\n%s' %
3022 ('\n'.join(files), owners_file, len(missing_lines),
3023 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173024
3025 results = []
3026 if errors:
vabrf5ce3bf92016-07-11 14:52:413027 if input_api.is_committing:
3028 output = output_api.PresubmitError
3029 else:
3030 output = output_api.PresubmitPromptWarning
3031 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593032 'Found OWNERS files that need to be updated for IPC security ' +
3033 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173034 long_text='\n\n'.join(errors)))
3035
3036 return results
3037
3038
Robert Sesek2c905332020-05-06 23:17:133039def _GetFilesUsingSecurityCriticalFunctions(input_api):
3040 """Checks affected files for changes to security-critical calls. This
3041 function checks the full change diff, to catch both additions/changes
3042 and removals.
3043
3044 Returns a dict keyed by file name, and the value is a set of detected
3045 functions.
3046 """
3047 # Map of function pretty name (displayed in an error) to the pattern to
3048 # match it with.
3049 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373050 'content::GetServiceSandboxType<>()':
3051 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133052 }
3053 _PATTERNS_TO_CHECK = {
3054 k: input_api.re.compile(v)
3055 for k, v in _PATTERNS_TO_CHECK.items()
3056 }
3057
3058 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3059 files_to_functions = {}
3060 for f in input_api.AffectedFiles():
3061 diff = f.GenerateScmDiff()
3062 for line in diff.split('\n'):
3063 # Not using just RightHandSideLines() because removing a
3064 # call to a security-critical function can be just as important
3065 # as adding or changing the arguments.
3066 if line.startswith('-') or (line.startswith('+') and
3067 not line.startswith('++')):
3068 for name, pattern in _PATTERNS_TO_CHECK.items():
3069 if pattern.search(line):
3070 path = f.LocalPath()
3071 if not path in files_to_functions:
3072 files_to_functions[path] = set()
3073 files_to_functions[path].add(name)
3074 return files_to_functions
3075
3076
Saagar Sanghavifceeaae2020-08-12 16:40:363077def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133078 """Checks that changes involving security-critical functions are reviewed
3079 by the security team.
3080 """
3081 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3082 if len(files_to_functions):
3083 owners_db = input_api.owners_db
3084 owner_email, reviewers = (
3085 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3086 input_api,
3087 owners_db.email_regexp,
3088 approval_needed=input_api.is_committing))
3089
3090 # Load the OWNERS file for security changes.
3091 owners_file = 'ipc/SECURITY_OWNERS'
3092 security_owners = owners_db.owners_rooted_at_file(owners_file)
3093
3094 has_security_owner = any([owner in reviewers for owner in security_owners])
3095 if not has_security_owner:
3096 msg = 'The following files change calls to security-sensive functions\n' \
3097 'that need to be reviewed by {}.\n'.format(owners_file)
3098 for path, names in files_to_functions.items():
3099 msg += ' {}\n'.format(path)
3100 for name in names:
3101 msg += ' {}\n'.format(name)
3102 msg += '\n'
3103
3104 if input_api.is_committing:
3105 output = output_api.PresubmitError
3106 else:
3107 output = output_api.PresubmitNotifyResult
3108 return [output(msg)]
3109
3110 return []
3111
3112
Saagar Sanghavifceeaae2020-08-12 16:40:363113def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263114 """Checks that set noparent is only used together with an OWNERS file in
3115 //build/OWNERS.setnoparent (see also
3116 //docs/code_reviews.md#owners-files-details)
3117 """
3118 errors = []
3119
3120 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3121 allowed_owners_files = set()
3122 with open(allowed_owners_files_file, 'r') as f:
3123 for line in f:
3124 line = line.strip()
3125 if not line or line.startswith('#'):
3126 continue
3127 allowed_owners_files.add(line)
3128
3129 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3130
3131 for f in input_api.AffectedFiles(include_deletes=False):
3132 if not f.LocalPath().endswith('OWNERS'):
3133 continue
3134
3135 found_owners_files = set()
3136 found_set_noparent_lines = dict()
3137
3138 # Parse the OWNERS file.
3139 for lineno, line in enumerate(f.NewContents(), 1):
3140 line = line.strip()
3141 if line.startswith('set noparent'):
3142 found_set_noparent_lines[''] = lineno
3143 if line.startswith('file://'):
3144 if line in allowed_owners_files:
3145 found_owners_files.add('')
3146 if line.startswith('per-file'):
3147 match = per_file_pattern.match(line)
3148 if match:
3149 glob = match.group(1).strip()
3150 directive = match.group(2).strip()
3151 if directive == 'set noparent':
3152 found_set_noparent_lines[glob] = lineno
3153 if directive.startswith('file://'):
3154 if directive in allowed_owners_files:
3155 found_owners_files.add(glob)
3156
3157 # Check that every set noparent line has a corresponding file:// line
3158 # listed in build/OWNERS.setnoparent.
3159 for set_noparent_line in found_set_noparent_lines:
3160 if set_noparent_line in found_owners_files:
3161 continue
3162 errors.append(' %s:%d' % (f.LocalPath(),
3163 found_set_noparent_lines[set_noparent_line]))
3164
3165 results = []
3166 if errors:
3167 if input_api.is_committing:
3168 output = output_api.PresubmitError
3169 else:
3170 output = output_api.PresubmitPromptWarning
3171 results.append(output(
3172 'Found the following "set noparent" restrictions in OWNERS files that '
3173 'do not include owners from build/OWNERS.setnoparent:',
3174 long_text='\n\n'.join(errors)))
3175 return results
3176
3177
Saagar Sanghavifceeaae2020-08-12 16:40:363178def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313179 """Checks that added or removed lines in non third party affected
3180 header files do not lead to new useless class or struct forward
3181 declaration.
jbriance9e12f162016-11-25 07:57:503182 """
3183 results = []
3184 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3185 input_api.re.MULTILINE)
3186 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3187 input_api.re.MULTILINE)
3188 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313189 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193190 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493191 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313192 continue
3193
jbriance9e12f162016-11-25 07:57:503194 if not f.LocalPath().endswith('.h'):
3195 continue
3196
3197 contents = input_api.ReadFile(f)
3198 fwd_decls = input_api.re.findall(class_pattern, contents)
3199 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3200
3201 useless_fwd_decls = []
3202 for decl in fwd_decls:
3203 count = sum(1 for _ in input_api.re.finditer(
3204 r'\b%s\b' % input_api.re.escape(decl), contents))
3205 if count == 1:
3206 useless_fwd_decls.append(decl)
3207
3208 if not useless_fwd_decls:
3209 continue
3210
3211 for line in f.GenerateScmDiff().splitlines():
3212 if (line.startswith('-') and not line.startswith('--') or
3213 line.startswith('+') and not line.startswith('++')):
3214 for decl in useless_fwd_decls:
3215 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3216 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243217 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503218 (f.LocalPath(), decl)))
3219 useless_fwd_decls.remove(decl)
3220
3221 return results
3222
Jinsong Fan91ebbbd2019-04-16 14:57:173223def _CheckAndroidDebuggableBuild(input_api, output_api):
3224 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3225 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3226 this is a debuggable build of Android.
3227 """
3228 build_type_check_pattern = input_api.re.compile(
3229 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3230
3231 errors = []
3232
3233 sources = lambda affected_file: input_api.FilterSourceFile(
3234 affected_file,
James Cook24a504192020-07-23 00:08:443235 files_to_skip=(_EXCLUDED_PATHS +
3236 _TEST_CODE_EXCLUDED_PATHS +
3237 input_api.DEFAULT_FILES_TO_SKIP +
3238 (r"^android_webview[\\/]support_library[\\/]"
3239 "boundary_interfaces[\\/]",
3240 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3241 r'^third_party[\\/].*',
3242 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3243 r"webview[\\/]chromium[\\/]License.*",)),
3244 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173245
3246 for f in input_api.AffectedSourceFiles(sources):
3247 for line_num, line in f.ChangedContents():
3248 if build_type_check_pattern.search(line):
3249 errors.append("%s:%d" % (f.LocalPath(), line_num))
3250
3251 results = []
3252
3253 if errors:
3254 results.append(output_api.PresubmitPromptWarning(
3255 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3256 ' Please use BuildInfo.isDebugAndroid() instead.',
3257 errors))
3258
3259 return results
jbriance9e12f162016-11-25 07:57:503260
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493261# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293262def _CheckAndroidToastUsage(input_api, output_api):
3263 """Checks that code uses org.chromium.ui.widget.Toast instead of
3264 android.widget.Toast (Chromium Toast doesn't force hardware
3265 acceleration on low-end devices, saving memory).
3266 """
3267 toast_import_pattern = input_api.re.compile(
3268 r'^import android\.widget\.Toast;$')
3269
3270 errors = []
3271
3272 sources = lambda affected_file: input_api.FilterSourceFile(
3273 affected_file,
James Cook24a504192020-07-23 00:08:443274 files_to_skip=(_EXCLUDED_PATHS +
3275 _TEST_CODE_EXCLUDED_PATHS +
3276 input_api.DEFAULT_FILES_TO_SKIP +
3277 (r'^chromecast[\\/].*',
3278 r'^remoting[\\/].*')),
3279 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293280
3281 for f in input_api.AffectedSourceFiles(sources):
3282 for line_num, line in f.ChangedContents():
3283 if toast_import_pattern.search(line):
3284 errors.append("%s:%d" % (f.LocalPath(), line_num))
3285
3286 results = []
3287
3288 if errors:
3289 results.append(output_api.PresubmitError(
3290 'android.widget.Toast usage is detected. Android toasts use hardware'
3291 ' acceleration, and can be\ncostly on low-end devices. Please use'
3292 ' org.chromium.ui.widget.Toast instead.\n'
3293 'Contact [email protected] if you have any questions.',
3294 errors))
3295
3296 return results
3297
3298
dgnaa68d5e2015-06-10 10:08:223299def _CheckAndroidCrLogUsage(input_api, output_api):
3300 """Checks that new logs using org.chromium.base.Log:
3301 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513302 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223303 """
pkotwicza1dd0b002016-05-16 14:41:043304
torne89540622017-03-24 19:41:303305 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043306 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303307 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043308 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303309 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043310 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3311 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093312 # The customtabs_benchmark is a small app that does not depend on Chromium
3313 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043314 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043315 ]
3316
dgnaa68d5e2015-06-10 10:08:223317 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123318 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3319 class_in_base_pattern = input_api.re.compile(
3320 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3321 has_some_log_import_pattern = input_api.re.compile(
3322 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223323 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553324 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223325 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463326 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553327 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223328
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463329 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443330 sources = lambda x: input_api.FilterSourceFile(x,
3331 files_to_check=[r'.*\.java$'],
3332 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123333
dgnaa68d5e2015-06-10 10:08:223334 tag_decl_errors = []
3335 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123336 tag_errors = []
dgn38736db2015-09-18 19:20:513337 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123338 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223339
3340 for f in input_api.AffectedSourceFiles(sources):
3341 file_content = input_api.ReadFile(f)
3342 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223343 # Per line checks
dgn87d9fb62015-06-12 09:15:123344 if (cr_log_import_pattern.search(file_content) or
3345 (class_in_base_pattern.search(file_content) and
3346 not has_some_log_import_pattern.search(file_content))):
3347 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223348 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553349 if rough_log_decl_pattern.search(line):
3350 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223351
3352 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123353 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223354 if match:
3355 has_modified_logs = True
3356
3357 # Make sure it uses "TAG"
3358 if not match.group('tag') == 'TAG':
3359 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123360 else:
3361 # Report non cr Log function calls in changed lines
3362 for line_num, line in f.ChangedContents():
3363 if log_call_pattern.search(line):
3364 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223365
3366 # Per file checks
3367 if has_modified_logs:
3368 # Make sure the tag is using the "cr" prefix and is not too long
3369 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513370 tag_name = match.group('name') if match else None
3371 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223372 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513373 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223374 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513375 elif '.' in tag_name:
3376 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223377
3378 results = []
3379 if tag_decl_errors:
3380 results.append(output_api.PresubmitPromptWarning(
3381 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513382 '"private static final String TAG = "<package tag>".\n'
3383 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223384 tag_decl_errors))
3385
3386 if tag_length_errors:
3387 results.append(output_api.PresubmitError(
3388 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513389 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223390 tag_length_errors))
3391
3392 if tag_errors:
3393 results.append(output_api.PresubmitPromptWarning(
3394 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3395 tag_errors))
3396
dgn87d9fb62015-06-12 09:15:123397 if util_log_errors:
dgn4401aa52015-04-29 16:26:173398 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123399 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3400 util_log_errors))
3401
dgn38736db2015-09-18 19:20:513402 if tag_with_dot_errors:
3403 results.append(output_api.PresubmitPromptWarning(
3404 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3405 tag_with_dot_errors))
3406
dgn4401aa52015-04-29 16:26:173407 return results
3408
3409
Yoland Yanb92fa522017-08-28 17:37:063410def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3411 """Checks that junit.framework.* is no longer used."""
3412 deprecated_junit_framework_pattern = input_api.re.compile(
3413 r'^import junit\.framework\..*;',
3414 input_api.re.MULTILINE)
3415 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443416 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063417 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133418 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063419 for line_num, line in f.ChangedContents():
3420 if deprecated_junit_framework_pattern.search(line):
3421 errors.append("%s:%d" % (f.LocalPath(), line_num))
3422
3423 results = []
3424 if errors:
3425 results.append(output_api.PresubmitError(
3426 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3427 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3428 ' if you have any question.', errors))
3429 return results
3430
3431
3432def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3433 """Checks that if new Java test classes have inheritance.
3434 Either the new test class is JUnit3 test or it is a JUnit4 test class
3435 with a base class, either case is undesirable.
3436 """
3437 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3438
3439 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443440 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063441 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133442 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063443 if not f.OldContents():
3444 class_declaration_start_flag = False
3445 for line_num, line in f.ChangedContents():
3446 if class_declaration_pattern.search(line):
3447 class_declaration_start_flag = True
3448 if class_declaration_start_flag and ' extends ' in line:
3449 errors.append('%s:%d' % (f.LocalPath(), line_num))
3450 if '{' in line:
3451 class_declaration_start_flag = False
3452
3453 results = []
3454 if errors:
3455 results.append(output_api.PresubmitPromptWarning(
3456 'The newly created files include Test classes that inherits from base'
3457 ' class. Please do not use inheritance in JUnit4 tests or add new'
3458 ' JUnit3 tests. Contact [email protected] if you have any'
3459 ' questions.', errors))
3460 return results
3461
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203462
yolandyan45001472016-12-21 21:12:423463def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3464 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3465 deprecated_annotation_import_pattern = input_api.re.compile(
3466 r'^import android\.test\.suitebuilder\.annotation\..*;',
3467 input_api.re.MULTILINE)
3468 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443469 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423470 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133471 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423472 for line_num, line in f.ChangedContents():
3473 if deprecated_annotation_import_pattern.search(line):
3474 errors.append("%s:%d" % (f.LocalPath(), line_num))
3475
3476 results = []
3477 if errors:
3478 results.append(output_api.PresubmitError(
3479 'Annotations in android.test.suitebuilder.annotation have been'
3480 ' deprecated since API level 24. Please use android.support.test.filters'
3481 ' from //third_party/android_support_test_runner:runner_java instead.'
3482 ' Contact [email protected] if you have any questions.', errors))
3483 return results
3484
3485
agrieve7b6479d82015-10-07 14:24:223486def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3487 """Checks if MDPI assets are placed in a correct directory."""
3488 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3489 ('/res/drawable/' in f.LocalPath() or
3490 '/res/drawable-ldrtl/' in f.LocalPath()))
3491 errors = []
3492 for f in input_api.AffectedFiles(include_deletes=False,
3493 file_filter=file_filter):
3494 errors.append(' %s' % f.LocalPath())
3495
3496 results = []
3497 if errors:
3498 results.append(output_api.PresubmitError(
3499 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3500 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3501 '/res/drawable-ldrtl/.\n'
3502 'Contact [email protected] if you have questions.', errors))
3503 return results
3504
3505
Nate Fischer535972b2017-09-16 01:06:183506def _CheckAndroidWebkitImports(input_api, output_api):
3507 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353508 android.webview.ValueCallback except in the WebView glue layer
3509 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183510 """
3511 valuecallback_import_pattern = input_api.re.compile(
3512 r'^import android\.webkit\.ValueCallback;$')
3513
3514 errors = []
3515
3516 sources = lambda affected_file: input_api.FilterSourceFile(
3517 affected_file,
James Cook24a504192020-07-23 00:08:443518 files_to_skip=(_EXCLUDED_PATHS +
3519 _TEST_CODE_EXCLUDED_PATHS +
3520 input_api.DEFAULT_FILES_TO_SKIP +
3521 (r'^android_webview[\\/]glue[\\/].*',
3522 r'^weblayer[\\/].*',)),
3523 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183524
3525 for f in input_api.AffectedSourceFiles(sources):
3526 for line_num, line in f.ChangedContents():
3527 if valuecallback_import_pattern.search(line):
3528 errors.append("%s:%d" % (f.LocalPath(), line_num))
3529
3530 results = []
3531
3532 if errors:
3533 results.append(output_api.PresubmitError(
3534 'android.webkit.ValueCallback usage is detected outside of the glue'
3535 ' layer. To stay compatible with the support library, android.webkit.*'
3536 ' classes should only be used inside the glue layer and'
3537 ' org.chromium.base.Callback should be used instead.',
3538 errors))
3539
3540 return results
3541
3542
Becky Zhou7c69b50992018-12-10 19:37:573543def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3544 """Checks Android XML styles """
3545 import sys
3546 original_sys_path = sys.path
3547 try:
3548 sys.path = sys.path + [input_api.os_path.join(
3549 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3550 import checkxmlstyle
3551 finally:
3552 # Restore sys.path to what it was before.
3553 sys.path = original_sys_path
3554
3555 if is_check_on_upload:
3556 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3557 else:
3558 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3559
3560
agrievef32bcc72016-04-04 14:57:403561class PydepsChecker(object):
3562 def __init__(self, input_api, pydeps_files):
3563 self._file_cache = {}
3564 self._input_api = input_api
3565 self._pydeps_files = pydeps_files
3566
3567 def _LoadFile(self, path):
3568 """Returns the list of paths within a .pydeps file relative to //."""
3569 if path not in self._file_cache:
3570 with open(path) as f:
3571 self._file_cache[path] = f.read()
3572 return self._file_cache[path]
3573
3574 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3575 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393576 pydeps_data = self._LoadFile(pydeps_path)
3577 uses_gn_paths = '--gn-paths' in pydeps_data
3578 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3579 if uses_gn_paths:
3580 # Paths look like: //foo/bar/baz
3581 return (e[2:] for e in entries)
3582 else:
3583 # Paths look like: path/relative/to/file.pydeps
3584 os_path = self._input_api.os_path
3585 pydeps_dir = os_path.dirname(pydeps_path)
3586 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403587
3588 def _CreateFilesToPydepsMap(self):
3589 """Returns a map of local_path -> list_of_pydeps."""
3590 ret = {}
3591 for pydep_local_path in self._pydeps_files:
3592 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3593 ret.setdefault(path, []).append(pydep_local_path)
3594 return ret
3595
3596 def ComputeAffectedPydeps(self):
3597 """Returns an iterable of .pydeps files that might need regenerating."""
3598 affected_pydeps = set()
3599 file_to_pydeps_map = None
3600 for f in self._input_api.AffectedFiles(include_deletes=True):
3601 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463602 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3603 # subrepositories. We can't figure out which files change, so re-check
3604 # all files.
3605 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383606 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3607 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403608 return self._pydeps_files
3609 elif local_path.endswith('.pydeps'):
3610 if local_path in self._pydeps_files:
3611 affected_pydeps.add(local_path)
3612 elif local_path.endswith('.py'):
3613 if file_to_pydeps_map is None:
3614 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3615 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3616 return affected_pydeps
3617
3618 def DetermineIfStale(self, pydeps_path):
3619 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413620 import difflib
John Budorick47ca3fe2018-02-10 00:53:103621 import os
3622
agrievef32bcc72016-04-04 14:57:403623 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033624 if old_pydeps_data:
3625 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393626 if '--output' not in cmd:
3627 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033628 old_contents = old_pydeps_data[2:]
3629 else:
3630 # A default cmd that should work in most cases (as long as pydeps filename
3631 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3632 # file is empty/new.
3633 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3634 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3635 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103636 env = dict(os.environ)
3637 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403638 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103639 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413640 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033641 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413642 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403643
3644
Tibor Goldschwendt360793f72019-06-25 18:23:493645def _ParseGclientArgs():
3646 args = {}
3647 with open('build/config/gclient_args.gni', 'r') as f:
3648 for line in f:
3649 line = line.strip()
3650 if not line or line.startswith('#'):
3651 continue
3652 attribute, value = line.split('=')
3653 args[attribute.strip()] = value.strip()
3654 return args
3655
3656
Saagar Sanghavifceeaae2020-08-12 16:40:363657def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403658 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403659 # This check is for Python dependency lists (.pydeps files), and involves
3660 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3661 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283662 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003663 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493664 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403665 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403666 results = []
3667 # First, check for new / deleted .pydeps.
3668 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033669 # Check whether we are running the presubmit check for a file in src.
3670 # f.LocalPath is relative to repo (src, or internal repo).
3671 # os_path.exists is relative to src repo.
3672 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3673 # to src and we can conclude that the pydeps is in src.
3674 if input_api.os_path.exists(f.LocalPath()):
3675 if f.LocalPath().endswith('.pydeps'):
3676 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3677 results.append(output_api.PresubmitError(
3678 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3679 'remove %s' % f.LocalPath()))
3680 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3681 results.append(output_api.PresubmitError(
3682 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3683 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403684
3685 if results:
3686 return results
3687
Mohamed Heikal7cd4d8312020-06-16 16:49:403688 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3689 affected_pydeps = set(checker.ComputeAffectedPydeps())
3690 affected_android_pydeps = affected_pydeps.intersection(
3691 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3692 if affected_android_pydeps and not is_android:
3693 results.append(output_api.PresubmitPromptOrNotify(
3694 'You have changed python files that may affect pydeps for android\n'
3695 'specific scripts. However, the relevant presumbit check cannot be\n'
3696 'run because you are not using an Android checkout. To validate that\n'
3697 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3698 'use the android-internal-presubmit optional trybot.\n'
3699 'Possibly stale pydeps files:\n{}'.format(
3700 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403701
Mohamed Heikal7cd4d8312020-06-16 16:49:403702 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3703 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403704 try:
phajdan.jr0d9878552016-11-04 10:49:413705 result = checker.DetermineIfStale(pydep_path)
3706 if result:
3707 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403708 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413709 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3710 'To regenerate, run:\n\n %s' %
3711 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403712 except input_api.subprocess.CalledProcessError as error:
3713 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3714 long_text=error.output)]
3715
3716 return results
3717
3718
Saagar Sanghavifceeaae2020-08-12 16:40:363719def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433720 """Checks to make sure no header files have |Singleton<|."""
3721 def FileFilter(affected_file):
3722 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443723 files_to_skip = (_EXCLUDED_PATHS +
3724 input_api.DEFAULT_FILES_TO_SKIP +
3725 (r"^base[\\/]memory[\\/]singleton\.h$",
3726 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3727 r"quic_singleton_impl\.h$"))
3728 return input_api.FilterSourceFile(affected_file,
3729 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433730
sergeyu34d21222015-09-16 00:11:443731 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433732 files = []
3733 for f in input_api.AffectedSourceFiles(FileFilter):
3734 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3735 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3736 contents = input_api.ReadFile(f)
3737 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243738 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433739 pattern.search(line)):
3740 files.append(f)
3741 break
3742
3743 if files:
yolandyandaabc6d2016-04-18 18:29:393744 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443745 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433746 'Please move them to an appropriate source file so that the ' +
3747 'template gets instantiated in a single compilation unit.',
3748 files) ]
3749 return []
3750
3751
[email protected]fd20b902014-05-09 02:14:533752_DEPRECATED_CSS = [
3753 # Values
3754 ( "-webkit-box", "flex" ),
3755 ( "-webkit-inline-box", "inline-flex" ),
3756 ( "-webkit-flex", "flex" ),
3757 ( "-webkit-inline-flex", "inline-flex" ),
3758 ( "-webkit-min-content", "min-content" ),
3759 ( "-webkit-max-content", "max-content" ),
3760
3761 # Properties
3762 ( "-webkit-background-clip", "background-clip" ),
3763 ( "-webkit-background-origin", "background-origin" ),
3764 ( "-webkit-background-size", "background-size" ),
3765 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443766 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533767
3768 # Functions
3769 ( "-webkit-gradient", "gradient" ),
3770 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3771 ( "-webkit-linear-gradient", "linear-gradient" ),
3772 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3773 ( "-webkit-radial-gradient", "radial-gradient" ),
3774 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3775]
3776
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203777
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493778# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363779def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533780 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253781 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343782 documentation and iOS CSS for dom distiller
3783 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253784 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533785 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493786 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443787 files_to_skip = (_EXCLUDED_PATHS +
3788 _TEST_CODE_EXCLUDED_PATHS +
3789 input_api.DEFAULT_FILES_TO_SKIP +
3790 (r"^chrome/common/extensions/docs",
3791 r"^chrome/docs",
3792 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3793 r"^components/neterror/resources/neterror.css",
3794 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253795 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443796 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533797 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3798 for line_num, line in fpath.ChangedContents():
3799 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023800 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533801 results.append(output_api.PresubmitError(
3802 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3803 (fpath.LocalPath(), line_num, deprecated_value, value)))
3804 return results
3805
mohan.reddyf21db962014-10-16 12:26:473806
Saagar Sanghavifceeaae2020-08-12 16:40:363807def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363808 bad_files = {}
3809 for f in input_api.AffectedFiles(include_deletes=False):
3810 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493811 not f.LocalPath().startswith('third_party/blink') and
3812 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363813 continue
3814
Daniel Bratell65b033262019-04-23 08:17:063815 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363816 continue
3817
Vaclav Brozekd5de76a2018-03-17 07:57:503818 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363819 if "#include" in line and "../" in line]
3820 if not relative_includes:
3821 continue
3822 bad_files[f.LocalPath()] = relative_includes
3823
3824 if not bad_files:
3825 return []
3826
3827 error_descriptions = []
3828 for file_path, bad_lines in bad_files.iteritems():
3829 error_description = file_path
3830 for line in bad_lines:
3831 error_description += '\n ' + line
3832 error_descriptions.append(error_description)
3833
3834 results = []
3835 results.append(output_api.PresubmitError(
3836 'You added one or more relative #include paths (including "../").\n'
3837 'These shouldn\'t be used because they can be used to include headers\n'
3838 'from code that\'s not correctly specified as a dependency in the\n'
3839 'relevant BUILD.gn file(s).',
3840 error_descriptions))
3841
3842 return results
3843
Takeshi Yoshinoe387aa32017-08-02 13:16:133844
Saagar Sanghavifceeaae2020-08-12 16:40:363845def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063846 """Check that nobody tries to include a cc file. It's a relatively
3847 common error which results in duplicate symbols in object
3848 files. This may not always break the build until someone later gets
3849 very confusing linking errors."""
3850 results = []
3851 for f in input_api.AffectedFiles(include_deletes=False):
3852 # We let third_party code do whatever it wants
3853 if (f.LocalPath().startswith('third_party') and
3854 not f.LocalPath().startswith('third_party/blink') and
3855 not f.LocalPath().startswith('third_party\\blink')):
3856 continue
3857
3858 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3859 continue
3860
3861 for _, line in f.ChangedContents():
3862 if line.startswith('#include "'):
3863 included_file = line.split('"')[1]
3864 if _IsCPlusPlusFile(input_api, included_file):
3865 # The most common naming for external files with C++ code,
3866 # apart from standard headers, is to call them foo.inc, but
3867 # Chromium sometimes uses foo-inc.cc so allow that as well.
3868 if not included_file.endswith(('.h', '-inc.cc')):
3869 results.append(output_api.PresubmitError(
3870 'Only header files or .inc files should be included in other\n'
3871 'C++ files. Compiling the contents of a cc file more than once\n'
3872 'will cause duplicate information in the build which may later\n'
3873 'result in strange link_errors.\n' +
3874 f.LocalPath() + ':\n ' +
3875 line))
3876
3877 return results
3878
3879
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203880def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3881 if not isinstance(key, ast.Str):
3882 return 'Key at line %d must be a string literal' % key.lineno
3883 if not isinstance(value, ast.Dict):
3884 return 'Value at line %d must be a dict' % value.lineno
3885 if len(value.keys) != 1:
3886 return 'Dict at line %d must have single entry' % value.lineno
3887 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3888 return (
3889 'Entry at line %d must have a string literal \'filepath\' as key' %
3890 value.lineno)
3891 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133892
Takeshi Yoshinoe387aa32017-08-02 13:16:133893
Sergey Ulanov4af16052018-11-08 02:41:463894def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203895 if not isinstance(key, ast.Str):
3896 return 'Key at line %d must be a string literal' % key.lineno
3897 if not isinstance(value, ast.List):
3898 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463899 for element in value.elts:
3900 if not isinstance(element, ast.Str):
3901 return 'Watchlist elements on line %d is not a string' % key.lineno
3902 if not email_regex.match(element.s):
3903 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3904 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203905 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133906
Takeshi Yoshinoe387aa32017-08-02 13:16:133907
Sergey Ulanov4af16052018-11-08 02:41:463908def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203909 mismatch_template = (
3910 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3911 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133912
Sergey Ulanov4af16052018-11-08 02:41:463913 email_regex = input_api.re.compile(
3914 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3915
3916 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203917 i = 0
3918 last_key = ''
3919 while True:
3920 if i >= len(wd_dict.keys):
3921 if i >= len(w_dict.keys):
3922 return None
3923 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3924 elif i >= len(w_dict.keys):
3925 return (
3926 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 wd_key = wd_dict.keys[i]
3929 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133930
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203931 result = _CheckWatchlistDefinitionsEntrySyntax(
3932 wd_key, wd_dict.values[i], ast)
3933 if result is not None:
3934 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133935
Sergey Ulanov4af16052018-11-08 02:41:463936 result = _CheckWatchlistsEntrySyntax(
3937 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203938 if result is not None:
3939 return 'Bad entry in WATCHLISTS dict: %s' % result
3940
3941 if wd_key.s != w_key.s:
3942 return mismatch_template % (
3943 '%s at line %d' % (wd_key.s, wd_key.lineno),
3944 '%s at line %d' % (w_key.s, w_key.lineno))
3945
3946 if wd_key.s < last_key:
3947 return (
3948 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3949 (wd_key.lineno, w_key.lineno))
3950 last_key = wd_key.s
3951
3952 i = i + 1
3953
3954
Sergey Ulanov4af16052018-11-08 02:41:463955def _CheckWATCHLISTSSyntax(expression, input_api):
3956 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203957 if not isinstance(expression, ast.Expression):
3958 return 'WATCHLISTS file must contain a valid expression'
3959 dictionary = expression.body
3960 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3961 return 'WATCHLISTS file must have single dict with exactly two entries'
3962
3963 first_key = dictionary.keys[0]
3964 first_value = dictionary.values[0]
3965 second_key = dictionary.keys[1]
3966 second_value = dictionary.values[1]
3967
3968 if (not isinstance(first_key, ast.Str) or
3969 first_key.s != 'WATCHLIST_DEFINITIONS' or
3970 not isinstance(first_value, ast.Dict)):
3971 return (
3972 'The first entry of the dict in WATCHLISTS file must be '
3973 'WATCHLIST_DEFINITIONS dict')
3974
3975 if (not isinstance(second_key, ast.Str) or
3976 second_key.s != 'WATCHLISTS' or
3977 not isinstance(second_value, ast.Dict)):
3978 return (
3979 'The second entry of the dict in WATCHLISTS file must be '
3980 'WATCHLISTS dict')
3981
Sergey Ulanov4af16052018-11-08 02:41:463982 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133983
3984
Saagar Sanghavifceeaae2020-08-12 16:40:363985def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133986 for f in input_api.AffectedFiles(include_deletes=False):
3987 if f.LocalPath() == 'WATCHLISTS':
3988 contents = input_api.ReadFile(f, 'r')
3989
3990 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203991 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133992 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203993 # Get an AST tree for it and scan the tree for detailed style checking.
3994 expression = input_api.ast.parse(
3995 contents, filename='WATCHLISTS', mode='eval')
3996 except ValueError as e:
3997 return [output_api.PresubmitError(
3998 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3999 except SyntaxError as e:
4000 return [output_api.PresubmitError(
4001 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4002 except TypeError as e:
4003 return [output_api.PresubmitError(
4004 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134005
Sergey Ulanov4af16052018-11-08 02:41:464006 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204007 if result is not None:
4008 return [output_api.PresubmitError(result)]
4009 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134010
4011 return []
4012
4013
Andrew Grieve1b290e4a22020-11-24 20:07:014014def CheckGnGlobForward(input_api, output_api):
4015 """Checks that forward_variables_from(invoker, "*") follows best practices.
4016
4017 As documented at //build/docs/writing_gn_templates.md
4018 """
4019 def gn_files(f):
4020 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4021
4022 problems = []
4023 for f in input_api.AffectedSourceFiles(gn_files):
4024 for line_num, line in f.ChangedContents():
4025 if 'forward_variables_from(invoker, "*")' in line:
4026 problems.append(
4027 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4028 f.LocalPath(), line_num))
4029
4030 if problems:
4031 return [output_api.PresubmitPromptWarning(
4032 'forward_variables_from("*") without exclusions',
4033 items=sorted(problems),
4034 long_text=('The variables "visibilty" and "test_only" should be '
4035 'explicitly listed in forward_variables_from(). For more '
4036 'details, see:\n'
4037 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4038 'build/docs/writing_gn_templates.md'
4039 '#Using-forward_variables_from'))]
4040 return []
4041
4042
Saagar Sanghavifceeaae2020-08-12 16:40:364043def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194044 """Checks that newly added header files have corresponding GN changes.
4045 Note that this is only a heuristic. To be precise, run script:
4046 build/check_gn_headers.py.
4047 """
4048
4049 def headers(f):
4050 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444051 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194052
4053 new_headers = []
4054 for f in input_api.AffectedSourceFiles(headers):
4055 if f.Action() != 'A':
4056 continue
4057 new_headers.append(f.LocalPath())
4058
4059 def gn_files(f):
James Cook24a504192020-07-23 00:08:444060 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194061
4062 all_gn_changed_contents = ''
4063 for f in input_api.AffectedSourceFiles(gn_files):
4064 for _, line in f.ChangedContents():
4065 all_gn_changed_contents += line
4066
4067 problems = []
4068 for header in new_headers:
4069 basename = input_api.os_path.basename(header)
4070 if basename not in all_gn_changed_contents:
4071 problems.append(header)
4072
4073 if problems:
4074 return [output_api.PresubmitPromptWarning(
4075 'Missing GN changes for new header files', items=sorted(problems),
4076 long_text='Please double check whether newly added header files need '
4077 'corresponding changes in gn or gni files.\nThis checking is only a '
4078 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4079 'Read https://crbug.com/661774 for more info.')]
4080 return []
4081
4082
Saagar Sanghavifceeaae2020-08-12 16:40:364083def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024084 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4085
4086 This assumes we won't intentionally reference one product from the other
4087 product.
4088 """
4089 all_problems = []
4090 test_cases = [{
4091 "filename_postfix": "google_chrome_strings.grd",
4092 "correct_name": "Chrome",
4093 "incorrect_name": "Chromium",
4094 }, {
4095 "filename_postfix": "chromium_strings.grd",
4096 "correct_name": "Chromium",
4097 "incorrect_name": "Chrome",
4098 }]
4099
4100 for test_case in test_cases:
4101 problems = []
4102 filename_filter = lambda x: x.LocalPath().endswith(
4103 test_case["filename_postfix"])
4104
4105 # Check each new line. Can yield false positives in multiline comments, but
4106 # easier than trying to parse the XML because messages can have nested
4107 # children, and associating message elements with affected lines is hard.
4108 for f in input_api.AffectedSourceFiles(filename_filter):
4109 for line_num, line in f.ChangedContents():
4110 if "<message" in line or "<!--" in line or "-->" in line:
4111 continue
4112 if test_case["incorrect_name"] in line:
4113 problems.append(
4114 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4115
4116 if problems:
4117 message = (
4118 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4119 % (test_case["correct_name"], test_case["correct_name"],
4120 test_case["incorrect_name"]))
4121 all_problems.append(
4122 output_api.PresubmitPromptWarning(message, items=problems))
4123
4124 return all_problems
4125
4126
Saagar Sanghavifceeaae2020-08-12 16:40:364127def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514128 # TODO(crbug.com/941824): We need to make sure the entries in
4129 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4130 # so that users of //buildtools in other projects get the same tooling
4131 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4132 # support to gclient, we can eliminate the duplication and delete
4133 # this presubmit check.
4134
4135 # Update this regexp if new revisions are added to the files.
4136 rev_regexp = input_api.re.compile(
Michael Savigny8b078012020-12-09 16:19:054137 ("'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version|"
4138 "reclient_version)':"))
Dirk Pranke3c18a382019-03-15 01:07:514139
4140 # If a user is changing one revision, they need to change the same
4141 # line in both files. This means that any given change should contain
4142 # exactly the same list of changed lines that match the regexps. The
4143 # replace(' ', '') call allows us to ignore whitespace changes to the
4144 # lines. The 'long_text' parameter to the error will contain the
4145 # list of changed lines in both files, which should make it easy enough
4146 # to spot the error without going overboard in this implementation.
Ola Rozenfeld355a1b4e2021-01-26 03:41:574147 buildtools_deps = input_api.os_path.join('buildtools', 'DEPS')
Dirk Pranke3c18a382019-03-15 01:07:514148 revs_changes = {
4149 'DEPS': {},
Ola Rozenfeld355a1b4e2021-01-26 03:41:574150 buildtools_deps: {},
Dirk Pranke3c18a382019-03-15 01:07:514151 }
4152 long_text = ''
4153
4154 for f in input_api.AffectedFiles(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574155 file_filter=lambda f: f.LocalPath() in ('DEPS', buildtools_deps)):
Dirk Pranke3c18a382019-03-15 01:07:514156 for line_num, line in f.ChangedContents():
4157 if rev_regexp.search(line):
4158 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4159 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4160
Ola Rozenfeld355a1b4e2021-01-26 03:41:574161 if set(revs_changes['DEPS']) != set(revs_changes[buildtools_deps]):
Dirk Pranke3c18a382019-03-15 01:07:514162 return [output_api.PresubmitError(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574163 'Change buildtools revisions in sync in both DEPS and ' +
4164 buildtools_deps + '.', long_text=long_text + '\n')]
Dirk Pranke3c18a382019-03-15 01:07:514165 else:
4166 return []
4167
4168
Saagar Sanghavifceeaae2020-08-12 16:40:364169def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364170 """Avoid large files, especially binary files, in the repository since
4171 git doesn't scale well for those. They will be in everyone's repo
4172 clones forever, forever making Chromium slower to clone and work
4173 with."""
4174
4175 # Uploading files to cloud storage is not trivial so we don't want
4176 # to set the limit too low, but the upper limit for "normal" large
4177 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4178 # anything over 20 MB is exceptional.
4179 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4180
4181 too_large_files = []
4182 for f in input_api.AffectedFiles():
4183 # Check both added and modified files (but not deleted files).
4184 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384185 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364186 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4187 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4188
4189 if too_large_files:
4190 message = (
4191 'Do not commit large files to git since git scales badly for those.\n' +
4192 'Instead put the large files in cloud storage and use DEPS to\n' +
4193 'fetch them.\n' + '\n'.join(too_large_files)
4194 )
4195 return [output_api.PresubmitError(
4196 'Too large files found in commit', long_text=message + '\n')]
4197 else:
4198 return []
4199
Max Morozb47503b2019-08-08 21:03:274200
Saagar Sanghavifceeaae2020-08-12 16:40:364201def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274202 """Checks specific for fuzz target sources."""
4203 EXPORTED_SYMBOLS = [
4204 'LLVMFuzzerInitialize',
4205 'LLVMFuzzerCustomMutator',
4206 'LLVMFuzzerCustomCrossOver',
4207 'LLVMFuzzerMutate',
4208 ]
4209
4210 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4211
4212 def FilterFile(affected_file):
4213 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444214 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4215 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274216
4217 return input_api.FilterSourceFile(
4218 affected_file,
James Cook24a504192020-07-23 00:08:444219 files_to_check=[files_to_check],
4220 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274221
4222 files_with_missing_header = []
4223 for f in input_api.AffectedSourceFiles(FilterFile):
4224 contents = input_api.ReadFile(f, 'r')
4225 if REQUIRED_HEADER in contents:
4226 continue
4227
4228 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4229 files_with_missing_header.append(f.LocalPath())
4230
4231 if not files_with_missing_header:
4232 return []
4233
4234 long_text = (
4235 'If you define any of the libFuzzer optional functions (%s), it is '
4236 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4237 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4238 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4239 'to access command line arguments passed to the fuzzer. Instead, prefer '
4240 'static initialization and shared resources as documented in '
4241 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4242 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4243 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4244 )
4245
4246 return [output_api.PresubmitPromptWarning(
4247 message="Missing '%s' in:" % REQUIRED_HEADER,
4248 items=files_with_missing_header,
4249 long_text=long_text)]
4250
4251
Mohamed Heikald048240a2019-11-12 16:57:374252def _CheckNewImagesWarning(input_api, output_api):
4253 """
4254 Warns authors who add images into the repo to make sure their images are
4255 optimized before committing.
4256 """
4257 images_added = False
4258 image_paths = []
4259 errors = []
4260 filter_lambda = lambda x: input_api.FilterSourceFile(
4261 x,
James Cook24a504192020-07-23 00:08:444262 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4263 + input_api.DEFAULT_FILES_TO_SKIP),
4264 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374265 )
4266 for f in input_api.AffectedFiles(
4267 include_deletes=False, file_filter=filter_lambda):
4268 local_path = f.LocalPath().lower()
4269 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4270 images_added = True
4271 image_paths.append(f)
4272 if images_added:
4273 errors.append(output_api.PresubmitPromptWarning(
4274 'It looks like you are trying to commit some images. If these are '
4275 'non-test-only images, please make sure to read and apply the tips in '
4276 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4277 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4278 'FYI only and will not block your CL on the CQ.', image_paths))
4279 return errors
4280
4281
Saagar Sanghavifceeaae2020-08-12 16:40:364282def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574283 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224284 results = []
dgnaa68d5e2015-06-10 10:08:224285 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174286 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224287 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294288 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064289 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4290 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424291 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184292 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574293 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374294 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154295 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574296 return results
4297
Saagar Sanghavifceeaae2020-08-12 16:40:364298def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574299 """Groups commit checks that target android code."""
4300 results = []
4301 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224302 return results
4303
Chris Hall59f8d0c72020-05-01 07:31:194304# TODO(chrishall): could we additionally match on any path owned by
4305# ui/accessibility/OWNERS ?
4306_ACCESSIBILITY_PATHS = (
4307 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4308 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4309 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4310 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4311 r"^content[\\/]browser[\\/]accessibility[\\/]",
4312 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4313 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4314 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4315 r"^ui[\\/]accessibility[\\/]",
4316 r"^ui[\\/]views[\\/]accessibility[\\/]",
4317)
4318
Saagar Sanghavifceeaae2020-08-12 16:40:364319def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194320 """Checks that commits to accessibility code contain an AX-Relnotes field in
4321 their commit message."""
4322 def FileFilter(affected_file):
4323 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444324 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194325
4326 # Only consider changes affecting accessibility paths.
4327 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4328 return []
4329
Akihiro Ota08108e542020-05-20 15:30:534330 # AX-Relnotes can appear in either the description or the footer.
4331 # When searching the description, require 'AX-Relnotes:' to appear at the
4332 # beginning of a line.
4333 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4334 description_has_relnotes = any(ax_regex.match(line)
4335 for line in input_api.change.DescriptionText().lower().splitlines())
4336
4337 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4338 'AX-Relnotes', [])
4339 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194340 return []
4341
4342 # TODO(chrishall): link to Relnotes documentation in message.
4343 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4344 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4345 "user-facing changes"
4346 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4347 "user-facing effects"
4348 "\n if this is confusing or annoying then please contact members "
4349 "of ui/accessibility/OWNERS.")
4350
4351 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224352
Saagar Sanghavifceeaae2020-08-12 16:40:364353def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394354 """Checks common to both upload and commit."""
4355 results = []
4356 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384357 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544358 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084359
4360 author = input_api.change.author_email
4361 if author and author not in _KNOWN_ROBOTS:
4362 results.extend(
4363 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4364
[email protected]9f919cc2013-07-31 03:04:044365 results.extend(
4366 input_api.canned_checks.CheckChangeHasNoTabs(
4367 input_api,
4368 output_api,
4369 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434370 results.extend(input_api.RunTests(
4371 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244372
Edward Lesmesce51df52020-08-04 22:10:174373 dirmd_bin = input_api.os_path.join(
4374 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4375 results.extend(input_api.RunTests(
4376 input_api.canned_checks.CheckDirMetadataFormat(
4377 input_api, output_api, dirmd_bin)))
4378 results.extend(
4379 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4380 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554381 results.extend(
4382 input_api.canned_checks.CheckNoNewMetadataInOwners(
4383 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174384
Vaclav Brozekcdc7defb2018-03-20 09:54:354385 for f in input_api.AffectedFiles():
4386 path, name = input_api.os_path.split(f.LocalPath())
4387 if name == 'PRESUBMIT.py':
4388 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004389 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4390 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074391 # The PRESUBMIT.py file (and the directory containing it) might
4392 # have been affected by being moved or removed, so only try to
4393 # run the tests if they still exist.
4394 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4395 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444396 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394397 return results
[email protected]1f7b4172010-01-28 01:17:344398
[email protected]b337cb5b2011-01-23 21:24:054399
Saagar Sanghavifceeaae2020-08-12 16:40:364400def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494401 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4402 if f.LocalPath().endswith(('.orig', '.rej'))]
4403 if problems:
4404 return [output_api.PresubmitError(
4405 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034406 else:
4407 return []
[email protected]b8079ae4a2012-12-05 19:56:494408
4409
Saagar Sanghavifceeaae2020-08-12 16:40:364410def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214411 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4412 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4413 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074414 include_re = input_api.re.compile(
4415 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4416 extension_re = input_api.re.compile(r'\.[a-z]+$')
4417 errors = []
4418 for f in input_api.AffectedFiles():
4419 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4420 continue
4421 found_line_number = None
4422 found_macro = None
4423 for line_num, line in f.ChangedContents():
4424 match = macro_re.search(line)
4425 if match:
4426 found_line_number = line_num
4427 found_macro = match.group(2)
4428 break
4429 if not found_line_number:
4430 continue
4431
4432 found_include = False
4433 for line in f.NewContents():
4434 if include_re.search(line):
4435 found_include = True
4436 break
4437 if found_include:
4438 continue
4439
4440 if not f.LocalPath().endswith('.h'):
4441 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4442 try:
4443 content = input_api.ReadFile(primary_header_path, 'r')
4444 if include_re.search(content):
4445 continue
4446 except IOError:
4447 pass
4448 errors.append('%s:%d %s macro is used without including build/'
4449 'build_config.h.'
4450 % (f.LocalPath(), found_line_number, found_macro))
4451 if errors:
4452 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4453 return []
4454
4455
[email protected]b00342e7f2013-03-26 16:21:544456def _DidYouMeanOSMacro(bad_macro):
4457 try:
4458 return {'A': 'OS_ANDROID',
4459 'B': 'OS_BSD',
4460 'C': 'OS_CHROMEOS',
4461 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444462 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544463 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444464 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544465 'N': 'OS_NACL',
4466 'O': 'OS_OPENBSD',
4467 'P': 'OS_POSIX',
4468 'S': 'OS_SOLARIS',
4469 'W': 'OS_WIN'}[bad_macro[3].upper()]
4470 except KeyError:
4471 return ''
4472
4473
4474def _CheckForInvalidOSMacrosInFile(input_api, f):
4475 """Check for sensible looking, totally invalid OS macros."""
4476 preprocessor_statement = input_api.re.compile(r'^\s*#')
4477 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4478 results = []
4479 for lnum, line in f.ChangedContents():
4480 if preprocessor_statement.search(line):
4481 for match in os_macro.finditer(line):
4482 if not match.group(1) in _VALID_OS_MACROS:
4483 good = _DidYouMeanOSMacro(match.group(1))
4484 did_you_mean = ' (did you mean %s?)' % good if good else ''
4485 results.append(' %s:%d %s%s' % (f.LocalPath(),
4486 lnum,
4487 match.group(1),
4488 did_you_mean))
4489 return results
4490
4491
Saagar Sanghavifceeaae2020-08-12 16:40:364492def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544493 """Check all affected files for invalid OS macros."""
4494 bad_macros = []
tzik3f295992018-12-04 20:32:234495 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474496 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544497 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4498
4499 if not bad_macros:
4500 return []
4501
4502 return [output_api.PresubmitError(
4503 'Possibly invalid OS macro[s] found. Please fix your code\n'
4504 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4505
lliabraa35bab3932014-10-01 12:16:444506
4507def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4508 """Check all affected files for invalid "if defined" macros."""
4509 ALWAYS_DEFINED_MACROS = (
4510 "TARGET_CPU_PPC",
4511 "TARGET_CPU_PPC64",
4512 "TARGET_CPU_68K",
4513 "TARGET_CPU_X86",
4514 "TARGET_CPU_ARM",
4515 "TARGET_CPU_MIPS",
4516 "TARGET_CPU_SPARC",
4517 "TARGET_CPU_ALPHA",
4518 "TARGET_IPHONE_SIMULATOR",
4519 "TARGET_OS_EMBEDDED",
4520 "TARGET_OS_IPHONE",
4521 "TARGET_OS_MAC",
4522 "TARGET_OS_UNIX",
4523 "TARGET_OS_WIN32",
4524 )
4525 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4526 results = []
4527 for lnum, line in f.ChangedContents():
4528 for match in ifdef_macro.finditer(line):
4529 if match.group(1) in ALWAYS_DEFINED_MACROS:
4530 always_defined = ' %s is always defined. ' % match.group(1)
4531 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4532 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4533 lnum,
4534 always_defined,
4535 did_you_mean))
4536 return results
4537
4538
Saagar Sanghavifceeaae2020-08-12 16:40:364539def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444540 """Check all affected files for invalid "if defined" macros."""
4541 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054542 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444543 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054544 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214545 continue
lliabraa35bab3932014-10-01 12:16:444546 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4547 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4548
4549 if not bad_macros:
4550 return []
4551
4552 return [output_api.PresubmitError(
4553 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4554 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4555 bad_macros)]
4556
4557
Saagar Sanghavifceeaae2020-08-12 16:40:364558def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044559 """Check for same IPC rules described in
4560 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4561 """
4562 base_pattern = r'IPC_ENUM_TRAITS\('
4563 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4564 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4565
4566 problems = []
4567 for f in input_api.AffectedSourceFiles(None):
4568 local_path = f.LocalPath()
4569 if not local_path.endswith('.h'):
4570 continue
4571 for line_number, line in f.ChangedContents():
4572 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4573 problems.append(
4574 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4575
4576 if problems:
4577 return [output_api.PresubmitPromptWarning(
4578 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4579 else:
4580 return []
4581
[email protected]b00342e7f2013-03-26 16:21:544582
Saagar Sanghavifceeaae2020-08-12 16:40:364583def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054584 """Check to make sure no files being submitted have long paths.
4585 This causes issues on Windows.
4586 """
4587 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194588 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054589 local_path = f.LocalPath()
4590 # Windows has a path limit of 260 characters. Limit path length to 200 so
4591 # that we have some extra for the prefix on dev machines and the bots.
4592 if len(local_path) > 200:
4593 problems.append(local_path)
4594
4595 if problems:
4596 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4597 else:
4598 return []
4599
4600
Saagar Sanghavifceeaae2020-08-12 16:40:364601def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144602 """Check that header files have proper guards against multiple inclusion.
4603 If a file should not have such guards (and it probably should) then it
4604 should include the string "no-include-guard-because-multiply-included".
4605 """
Daniel Bratell6a75baef62018-06-04 10:04:454606 def is_chromium_header_file(f):
4607 # We only check header files under the control of the Chromium
4608 # project. That is, those outside third_party apart from
4609 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324610 # We also exclude *_message_generator.h headers as they use
4611 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454612 file_with_path = input_api.os_path.normpath(f.LocalPath())
4613 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324614 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454615 (not file_with_path.startswith('third_party') or
4616 file_with_path.startswith(
4617 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144618
4619 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344620 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144621
4622 errors = []
4623
Daniel Bratell6a75baef62018-06-04 10:04:454624 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144625 guard_name = None
4626 guard_line_number = None
4627 seen_guard_end = False
4628
4629 file_with_path = input_api.os_path.normpath(f.LocalPath())
4630 base_file_name = input_api.os_path.splitext(
4631 input_api.os_path.basename(file_with_path))[0]
4632 upper_base_file_name = base_file_name.upper()
4633
4634 expected_guard = replace_special_with_underscore(
4635 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144636
4637 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574638 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4639 # are too many (1000+) files with slight deviations from the
4640 # coding style. The most important part is that the include guard
4641 # is there, and that it's unique, not the name so this check is
4642 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144643 #
4644 # As code becomes more uniform, this could be made stricter.
4645
4646 guard_name_pattern_list = [
4647 # Anything with the right suffix (maybe with an extra _).
4648 r'\w+_H__?',
4649
Daniel Bratell39b5b062018-05-16 18:09:574650 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144651 r'\w+_h',
4652
4653 # Anything including the uppercase name of the file.
4654 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4655 upper_base_file_name)) + r'\w*',
4656 ]
4657 guard_name_pattern = '|'.join(guard_name_pattern_list)
4658 guard_pattern = input_api.re.compile(
4659 r'#ifndef\s+(' + guard_name_pattern + ')')
4660
4661 for line_number, line in enumerate(f.NewContents()):
4662 if 'no-include-guard-because-multiply-included' in line:
4663 guard_name = 'DUMMY' # To not trigger check outside the loop.
4664 break
4665
4666 if guard_name is None:
4667 match = guard_pattern.match(line)
4668 if match:
4669 guard_name = match.group(1)
4670 guard_line_number = line_number
4671
Daniel Bratell39b5b062018-05-16 18:09:574672 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454673 # don't match the chromium style guide, but new files should
4674 # get it right.
4675 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574676 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144677 errors.append(output_api.PresubmitPromptWarning(
4678 'Header using the wrong include guard name %s' % guard_name,
4679 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574680 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144681 else:
4682 # The line after #ifndef should have a #define of the same name.
4683 if line_number == guard_line_number + 1:
4684 expected_line = '#define %s' % guard_name
4685 if line != expected_line:
4686 errors.append(output_api.PresubmitPromptWarning(
4687 'Missing "%s" for include guard' % expected_line,
4688 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4689 'Expected: %r\nGot: %r' % (expected_line, line)))
4690
4691 if not seen_guard_end and line == '#endif // %s' % guard_name:
4692 seen_guard_end = True
4693 elif seen_guard_end:
4694 if line.strip() != '':
4695 errors.append(output_api.PresubmitPromptWarning(
4696 'Include guard %s not covering the whole file' % (
4697 guard_name), [f.LocalPath()]))
4698 break # Nothing else to check and enough to warn once.
4699
4700 if guard_name is None:
4701 errors.append(output_api.PresubmitPromptWarning(
4702 'Missing include guard %s' % expected_guard,
4703 [f.LocalPath()],
4704 'Missing include guard in %s\n'
4705 'Recommended name: %s\n'
4706 'This check can be disabled by having the string\n'
4707 'no-include-guard-because-multiply-included in the header.' %
4708 (f.LocalPath(), expected_guard)))
4709
4710 return errors
4711
4712
Saagar Sanghavifceeaae2020-08-12 16:40:364713def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234714 """Check source code and known ascii text files for Windows style line
4715 endings.
4716 """
earthdok1b5e0ee2015-03-10 15:19:104717 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234718
4719 file_inclusion_pattern = (
4720 known_text_files,
4721 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4722 )
4723
mostynbb639aca52015-01-07 20:31:234724 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534725 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444726 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534727 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504728 include_file = False
4729 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234730 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504731 include_file = True
4732 if include_file:
4733 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234734
4735 if problems:
4736 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4737 'these files to contain Windows style line endings?\n' +
4738 '\n'.join(problems))]
4739
4740 return []
4741
4742
Saagar Sanghavifceeaae2020-08-12 16:40:364743def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134744 """Checks that all source files use SYSLOG properly."""
4745 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364746 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564747 for line_number, line in f.ChangedContents():
4748 if 'SYSLOG' in line:
4749 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4750
pastarmovj89f7ee12016-09-20 14:58:134751 if syslog_files:
4752 return [output_api.PresubmitPromptWarning(
4753 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4754 ' calls.\nFiles to check:\n', items=syslog_files)]
4755 return []
4756
4757
[email protected]1f7b4172010-01-28 01:17:344758def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364759 if input_api.version < [2, 0, 0]:
4760 return [output_api.PresubmitError("Your depot_tools is out of date. "
4761 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4762 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344763 results = []
scottmg39b29952014-12-08 18:31:284764 results.extend(
jam93a6ee792017-02-08 23:59:224765 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544766 return results
[email protected]ca8d1982009-02-19 16:33:124767
4768
[email protected]1bfb8322014-04-23 01:02:414769def GetTryServerMasterForBot(bot):
4770 """Returns the Try Server master for the given bot.
4771
[email protected]0bb112362014-07-26 04:38:324772 It tries to guess the master from the bot name, but may still fail
4773 and return None. There is no longer a default master.
4774 """
4775 # Potentially ambiguous bot names are listed explicitly.
4776 master_map = {
tandriie5587792016-07-14 00:34:504777 'chromium_presubmit': 'master.tryserver.chromium.linux',
4778 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414779 }
[email protected]0bb112362014-07-26 04:38:324780 master = master_map.get(bot)
4781 if not master:
wnwen4fbaab82016-05-25 12:54:364782 if 'android' in bot:
tandriie5587792016-07-14 00:34:504783 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364784 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504785 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324786 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504787 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324788 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504789 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324790 return master
[email protected]1bfb8322014-04-23 01:02:414791
4792
[email protected]ca8d1982009-02-19 16:33:124793def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364794 if input_api.version < [2, 0, 0]:
4795 return [output_api.PresubmitError("Your depot_tools is out of date. "
4796 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4797 "but your version is %d.%d.%d" % tuple(input_api.version))]
4798
[email protected]fe5f57c52009-06-05 14:25:544799 results = []
[email protected]fe5f57c52009-06-05 14:25:544800 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274801 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344802 input_api,
4803 output_api,
[email protected]2fdd1f362013-01-16 03:56:034804 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274805
jam93a6ee792017-02-08 23:59:224806 results.extend(
4807 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544808 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4809 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384810 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4811 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414812 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4813 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544814 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144815
4816
Saagar Sanghavifceeaae2020-08-12 16:40:364817def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264818 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024819 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4820 # footer is set to true.
4821 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264822 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024823 footer.lower()
4824 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264825 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024826
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144827 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264828 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144829 import sys
4830 from io import StringIO
4831
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144832 new_or_added_paths = set(f.LocalPath()
4833 for f in input_api.AffectedFiles()
4834 if (f.Action() == 'A' or f.Action() == 'M'))
4835 removed_paths = set(f.LocalPath()
4836 for f in input_api.AffectedFiles(include_deletes=True)
4837 if f.Action() == 'D')
4838
Andrew Grieve0e8790c2020-09-03 17:27:324839 affected_grds = [
4840 f for f in input_api.AffectedFiles()
4841 if f.LocalPath().endswith(('.grd', '.grdp'))
4842 ]
4843 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164844 if not affected_grds:
4845 return []
4846
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144847 affected_png_paths = [f.AbsoluteLocalPath()
4848 for f in input_api.AffectedFiles()
4849 if (f.LocalPath().endswith('.png'))]
4850
4851 # Check for screenshots. Developers can upload screenshots using
4852 # tools/translation/upload_screenshots.py which finds and uploads
4853 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4854 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4855 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4856 #
4857 # The logic here is as follows:
4858 #
4859 # - If the CL has a .png file under the screenshots directory for a grd
4860 # file, warn the developer. Actual images should never be checked into the
4861 # Chrome repo.
4862 #
4863 # - If the CL contains modified or new messages in grd files and doesn't
4864 # contain the corresponding .sha1 files, warn the developer to add images
4865 # and upload them via tools/translation/upload_screenshots.py.
4866 #
4867 # - If the CL contains modified or new messages in grd files and the
4868 # corresponding .sha1 files, everything looks good.
4869 #
4870 # - If the CL contains removed messages in grd files but the corresponding
4871 # .sha1 files aren't removed, warn the developer to remove them.
4872 unnecessary_screenshots = []
4873 missing_sha1 = []
4874 unnecessary_sha1_files = []
4875
Rainhard Findlingfc31844c52020-05-15 09:58:264876 # This checks verifies that the ICU syntax of messages this CL touched is
4877 # valid, and reports any found syntax errors.
4878 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4879 # without developers being aware of them. Later on, such ICU syntax errors
4880 # break message extraction for translation, hence would block Chromium
4881 # translations until they are fixed.
4882 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144883
4884 def _CheckScreenshotAdded(screenshots_dir, message_id):
4885 sha1_path = input_api.os_path.join(
4886 screenshots_dir, message_id + '.png.sha1')
4887 if sha1_path not in new_or_added_paths:
4888 missing_sha1.append(sha1_path)
4889
4890
4891 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4892 sha1_path = input_api.os_path.join(
4893 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034894 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144895 unnecessary_sha1_files.append(sha1_path)
4896
Rainhard Findlingfc31844c52020-05-15 09:58:264897
4898 def _ValidateIcuSyntax(text, level, signatures):
4899 """Validates ICU syntax of a text string.
4900
4901 Check if text looks similar to ICU and checks for ICU syntax correctness
4902 in this case. Reports various issues with ICU syntax and values of
4903 variants. Supports checking of nested messages. Accumulate information of
4904 each ICU messages found in the text for further checking.
4905
4906 Args:
4907 text: a string to check.
4908 level: a number of current nesting level.
4909 signatures: an accumulator, a list of tuple of (level, variable,
4910 kind, variants).
4911
4912 Returns:
4913 None if a string is not ICU or no issue detected.
4914 A tuple of (message, start index, end index) if an issue detected.
4915 """
4916 valid_types = {
4917 'plural': (frozenset(
4918 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4919 frozenset(['=1', 'other'])),
4920 'selectordinal': (frozenset(
4921 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4922 frozenset(['one', 'other'])),
4923 'select': (frozenset(), frozenset(['other'])),
4924 }
4925
4926 # Check if the message looks like an attempt to use ICU
4927 # plural. If yes - check if its syntax strictly matches ICU format.
4928 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4929 if not like:
4930 signatures.append((level, None, None, None))
4931 return
4932
4933 # Check for valid prefix and suffix
4934 m = re.match(
4935 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4936 r'(plural|selectordinal|select),\s*'
4937 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4938 if not m:
4939 return (('This message looks like an ICU plural, '
4940 'but does not follow ICU syntax.'), like.start(), like.end())
4941 starting, variable, kind, variant_pairs = m.groups()
4942 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4943 if depth:
4944 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4945 len(text))
4946 first = text[0]
4947 ending = text[last_pos:]
4948 if not starting:
4949 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4950 last_pos)
4951 if not ending or '}' not in ending:
4952 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4953 last_pos)
4954 elif first != '{':
4955 return (
4956 ('Invalid ICU format. Extra characters at the start of a complex '
4957 'message (go/icu-message-migration): "%s"') %
4958 starting, 0, len(starting))
4959 elif ending != '}':
4960 return (('Invalid ICU format. Extra characters at the end of a complex '
4961 'message (go/icu-message-migration): "%s"')
4962 % ending, last_pos - 1, len(text) - 1)
4963 if kind not in valid_types:
4964 return (('Unknown ICU message type %s. '
4965 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4966 known, required = valid_types[kind]
4967 defined_variants = set()
4968 for variant, variant_range, value, value_range in variants:
4969 start, end = variant_range
4970 if variant in defined_variants:
4971 return ('Variant "%s" is defined more than once' % variant,
4972 start, end)
4973 elif known and variant not in known:
4974 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4975 start, end)
4976 defined_variants.add(variant)
4977 # Check for nested structure
4978 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4979 if res:
4980 return (res[0], res[1] + value_range[0] + 1,
4981 res[2] + value_range[0] + 1)
4982 missing = required - defined_variants
4983 if missing:
4984 return ('Required variants missing: %s' % ', '.join(missing), 0,
4985 len(text))
4986 signatures.append((level, variable, kind, defined_variants))
4987
4988
4989 def _ParseIcuVariants(text, offset=0):
4990 """Parse variants part of ICU complex message.
4991
4992 Builds a tuple of variant names and values, as well as
4993 their offsets in the input string.
4994
4995 Args:
4996 text: a string to parse
4997 offset: additional offset to add to positions in the text to get correct
4998 position in the complete ICU string.
4999
5000 Returns:
5001 List of tuples, each tuple consist of four fields: variant name,
5002 variant name span (tuple of two integers), variant value, value
5003 span (tuple of two integers).
5004 """
5005 depth, start, end = 0, -1, -1
5006 variants = []
5007 key = None
5008 for idx, char in enumerate(text):
5009 if char == '{':
5010 if not depth:
5011 start = idx
5012 chunk = text[end + 1:start]
5013 key = chunk.strip()
5014 pos = offset + end + 1 + chunk.find(key)
5015 span = (pos, pos + len(key))
5016 depth += 1
5017 elif char == '}':
5018 if not depth:
5019 return variants, depth, offset + idx
5020 depth -= 1
5021 if not depth:
5022 end = idx
5023 variants.append((key, span, text[start:end + 1], (offset + start,
5024 offset + end + 1)))
5025 return variants, depth, offset + end + 1
5026
meacer8c0d3832019-12-26 21:46:165027 try:
5028 old_sys_path = sys.path
5029 sys.path = sys.path + [input_api.os_path.join(
5030 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5031 from helper import grd_helper
5032 finally:
5033 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145034
5035 for f in affected_grds:
5036 file_path = f.LocalPath()
5037 old_id_to_msg_map = {}
5038 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385039 # Note that this code doesn't check if the file has been deleted. This is
5040 # OK because it only uses the old and new file contents and doesn't load
5041 # the file via its path.
5042 # It's also possible that a file's content refers to a renamed or deleted
5043 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5044 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5045 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145046 if file_path.endswith('.grdp'):
5047 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585048 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395049 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145050 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585051 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395052 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145053 else:
meacerff8a9b62019-12-10 19:43:585054 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145055 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585056 old_id_to_msg_map = grd_helper.GetGrdMessages(
5057 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145058 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585059 new_id_to_msg_map = grd_helper.GetGrdMessages(
5060 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145061
Rainhard Findlingd8d04372020-08-13 13:30:095062 grd_name, ext = input_api.os_path.splitext(
5063 input_api.os_path.basename(file_path))
5064 screenshots_dir = input_api.os_path.join(
5065 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5066
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145067 # Compute added, removed and modified message IDs.
5068 old_ids = set(old_id_to_msg_map)
5069 new_ids = set(new_id_to_msg_map)
5070 added_ids = new_ids - old_ids
5071 removed_ids = old_ids - new_ids
5072 modified_ids = set([])
5073 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355074 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095075 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5076 # The message content itself changed. Require an updated screenshot.
5077 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355078 elif old_id_to_msg_map[key].attrs['meaning'] != \
5079 new_id_to_msg_map[key].attrs['meaning']:
5080 # The message meaning changed. Ensure there is a screenshot for it.
5081 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5082 if sha1_path not in new_or_added_paths and not \
5083 input_api.os_path.exists(sha1_path):
5084 # There is neither a previous screenshot nor is a new one added now.
5085 # Require a screenshot.
5086 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145087
Rainhard Findlingfc31844c52020-05-15 09:58:265088 if run_screenshot_check:
5089 # Check the screenshot directory for .png files. Warn if there is any.
5090 for png_path in affected_png_paths:
5091 if png_path.startswith(screenshots_dir):
5092 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145093
Rainhard Findlingfc31844c52020-05-15 09:58:265094 for added_id in added_ids:
5095 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145096
Rainhard Findlingfc31844c52020-05-15 09:58:265097 for modified_id in modified_ids:
5098 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145099
Rainhard Findlingfc31844c52020-05-15 09:58:265100 for removed_id in removed_ids:
5101 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5102
5103 # Check new and changed strings for ICU syntax errors.
5104 for key in added_ids.union(modified_ids):
5105 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5106 err = _ValidateIcuSyntax(msg, 0, [])
5107 if err is not None:
5108 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145109
5110 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265111 if run_screenshot_check:
5112 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005113 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265114 'Do not include actual screenshots in the changelist. Run '
5115 'tools/translate/upload_screenshots.py to upload them instead:',
5116 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117
Rainhard Findlingfc31844c52020-05-15 09:58:265118 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005119 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265120 'You are adding or modifying UI strings.\n'
5121 'To ensure the best translations, take screenshots of the relevant UI '
5122 '(https://g.co/chrome/translation) and add these files to your '
5123 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145124
Rainhard Findlingfc31844c52020-05-15 09:58:265125 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005126 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265127 'You removed strings associated with these files. Remove:',
5128 sorted(unnecessary_sha1_files)))
5129 else:
5130 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5131 'screenshots check.'))
5132
5133 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075134 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265135 'ICU syntax errors were found in the following strings (problems or '
5136 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
5138 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125139
5140
Saagar Sanghavifceeaae2020-08-12 16:40:365141def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125142 repo_root=None,
5143 translation_expectations_path=None,
5144 grd_files=None):
5145 import sys
5146 affected_grds = [f for f in input_api.AffectedFiles()
5147 if (f.LocalPath().endswith('.grd') or
5148 f.LocalPath().endswith('.grdp'))]
5149 if not affected_grds:
5150 return []
5151
5152 try:
5153 old_sys_path = sys.path
5154 sys.path = sys.path + [
5155 input_api.os_path.join(
5156 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5157 from helper import git_helper
5158 from helper import translation_helper
5159 finally:
5160 sys.path = old_sys_path
5161
5162 # Check that translation expectations can be parsed and we can get a list of
5163 # translatable grd files. |repo_root| and |translation_expectations_path| are
5164 # only passed by tests.
5165 if not repo_root:
5166 repo_root = input_api.PresubmitLocalPath()
5167 if not translation_expectations_path:
5168 translation_expectations_path = input_api.os_path.join(
5169 repo_root, 'tools', 'gritsettings',
5170 'translation_expectations.pyl')
5171 if not grd_files:
5172 grd_files = git_helper.list_grds_in_repository(repo_root)
5173
dpapad8e21b472020-10-23 17:15:035174 # Ignore bogus grd files used only for testing
5175 # ui/webui/resoucres/tools/generate_grd.py.
5176 ignore_path = input_api.os_path.join(
5177 'ui', 'webui', 'resources', 'tools', 'tests')
5178 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5179
Mustafa Emre Acer51f2f742020-03-09 19:41:125180 try:
5181 translation_helper.get_translatable_grds(repo_root, grd_files,
5182 translation_expectations_path)
5183 except Exception as e:
5184 return [output_api.PresubmitNotifyResult(
5185 'Failed to get a list of translatable grd files. This happens when:\n'
5186 ' - One of the modified grd or grdp files cannot be parsed or\n'
5187 ' - %s is not updated.\n'
5188 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5189 return []
Ken Rockotc31f4832020-05-29 18:58:515190
5191
Saagar Sanghavifceeaae2020-08-12 16:40:365192def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515193 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095194 changed_mojoms = input_api.AffectedFiles(
5195 include_deletes=True,
5196 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515197 delta = []
5198 for mojom in changed_mojoms:
5199 old_contents = ''.join(mojom.OldContents()) or None
5200 new_contents = ''.join(mojom.NewContents()) or None
5201 delta.append({
5202 'filename': mojom.LocalPath(),
5203 'old': '\n'.join(mojom.OldContents()) or None,
5204 'new': '\n'.join(mojom.NewContents()) or None,
5205 })
5206
5207 process = input_api.subprocess.Popen(
5208 [input_api.python_executable,
5209 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5210 'public', 'tools', 'mojom',
5211 'check_stable_mojom_compatibility.py'),
5212 '--src-root', input_api.PresubmitLocalPath()],
5213 stdin=input_api.subprocess.PIPE,
5214 stdout=input_api.subprocess.PIPE,
5215 stderr=input_api.subprocess.PIPE,
5216 universal_newlines=True)
5217 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5218 if process.returncode:
5219 return [output_api.PresubmitError(
5220 'One or more [Stable] mojom definitions appears to have been changed '
5221 'in a way that is not backward-compatible.',
5222 long_text=error)]
5223 return []
Dominic Battre645d42342020-12-04 16:14:105224
5225def CheckDeprecationOfPreferences(input_api, output_api):
5226 """Removing a preference should come with a deprecation."""
5227
5228 def FilterFile(affected_file):
5229 """Accept only .cc files and the like."""
5230 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5231 files_to_skip = (_EXCLUDED_PATHS +
5232 _TEST_CODE_EXCLUDED_PATHS +
5233 input_api.DEFAULT_FILES_TO_SKIP)
5234 return input_api.FilterSourceFile(
5235 affected_file,
5236 files_to_check=file_inclusion_pattern,
5237 files_to_skip=files_to_skip)
5238
5239 def ModifiedLines(affected_file):
5240 """Returns a list of tuples (line number, line text) of added and removed
5241 lines.
5242
5243 Deleted lines share the same line number as the previous line.
5244
5245 This relies on the scm diff output describing each changed code section
5246 with a line of the form
5247
5248 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5249 """
5250 line_num = 0
5251 modified_lines = []
5252 for line in affected_file.GenerateScmDiff().splitlines():
5253 # Extract <new line num> of the patch fragment (see format above).
5254 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5255 if m:
5256 line_num = int(m.groups(1)[0])
5257 continue
5258 if ((line.startswith('+') and not line.startswith('++')) or
5259 (line.startswith('-') and not line.startswith('--'))):
5260 modified_lines.append((line_num, line))
5261
5262 if not line.startswith('-'):
5263 line_num += 1
5264 return modified_lines
5265
5266 def FindLineWith(lines, needle):
5267 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5268
5269 If 0 or >1 lines contain `needle`, -1 is returned.
5270 """
5271 matching_line_numbers = [
5272 # + 1 for 1-based counting of line numbers.
5273 i + 1 for i, line
5274 in enumerate(lines)
5275 if needle in line]
5276 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5277
5278 def ModifiedPrefMigration(affected_file):
5279 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5280 # Determine first and last lines of MigrateObsolete.*Pref functions.
5281 new_contents = affected_file.NewContents();
5282 range_1 = (
5283 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5284 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5285 range_2 = (
5286 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5287 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5288 if (-1 in range_1 + range_2):
5289 raise Exception(
5290 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5291
5292 # Check whether any of the modified lines are part of the
5293 # MigrateObsolete.*Pref functions.
5294 for line_nr, line in ModifiedLines(affected_file):
5295 if (range_1[0] <= line_nr <= range_1[1] or
5296 range_2[0] <= line_nr <= range_2[1]):
5297 return True
5298 return False
5299
5300 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5301 browser_prefs_file_pattern = input_api.re.compile(
5302 r'chrome/browser/prefs/browser_prefs.cc')
5303
5304 changes = input_api.AffectedFiles(include_deletes=True,
5305 file_filter=FilterFile)
5306 potential_problems = []
5307 for f in changes:
5308 for line in f.GenerateScmDiff().splitlines():
5309 # Check deleted lines for pref registrations.
5310 if (line.startswith('-') and not line.startswith('--') and
5311 register_pref_pattern.search(line)):
5312 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5313
5314 if browser_prefs_file_pattern.search(f.LocalPath()):
5315 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5316 # assume that they knew that they have to deprecate preferences and don't
5317 # warn.
5318 try:
5319 if ModifiedPrefMigration(f):
5320 return []
5321 except Exception as e:
5322 return [output_api.PresubmitError(str(e))]
5323
5324 if potential_problems:
5325 return [output_api.PresubmitPromptWarning(
5326 'Discovered possible removal of preference registrations.\n\n'
5327 'Please make sure to properly deprecate preferences by clearing their\n'
5328 'value for a couple of milestones before finally removing the code.\n'
5329 'Otherwise data may stay in the preferences files forever. See\n'
5330 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5331 'This may be a false positive warning (e.g. if you move preference\n'
5332 'registrations to a different place).\n',
5333 potential_problems
5334 )]
5335 return []