blob: 211e615024f04c26e9fe5c1697d06b0e464df9c9 [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 Cooperb3f1af662021-02-01 19:47:26334 "^chrome/browser/ash/accessibility/",
Alexander Cooper6b447b22020-07-22 00:47:18335 '^chrome/browser/media_galleries/',
Alexander Cooperb3f1af662021-02-01 19:47:26336 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26337 "^chrome/browser/prefetch/no_state_prefetch/",
338 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18339 '^chrome/browser/resources/chromeos/accessibility/',
Alexander Cooper6b447b22020-07-22 00:47:18340 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26341 "^components/browsing_data/content/",
Alexander Cooperb3f1af662021-02-01 19:47:26342 "^components/feature_engagement/internal/",
343 "^docs/callback\\.md", # Intentional
344 "^docs/webui_explainer\\.md",
345 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
346 "^docs/security/mojo\\.md",
347 "^docs/threading_and_tasks\\.md",
348 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20349 '^extensions/browser/',
350 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51351 '^ppapi/proxy/',
Alexander Cooperb3f1af662021-02-01 19:47:26352 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
353 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51354 '^tools/clang/base_bind_rewriters/', # Intentional.
355 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51356))
[email protected]127f18ec2012-06-16 05:05:59357
Alexander Cooper46a92712021-01-30 00:00:20358# Directories that contain deprecated CallbackList types.
359# Find sub-directories from a given directory by running:
360# for i in `find . -maxdepth 1 -type d|sort`; do
361# echo "-- $i"
362# (cd $i; git grep -nP 'base::CallbackList<'|wc -l)
363# done
364#
365# TODO(crbug.com/1113007): Remove (or narrow the scope of) paths from this list
366# when they have been converted to modern callback list types (OnceCallback,
367# RepeatingCallback) in order to enable presubmit checks for them and prevent
368# regressions.
369_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST = '|'.join((
370 r'^chrome/browser/android/oom_intervention/near_oom_monitor\.h',
371 r'^chrome/browser/ash/account_manager/child_account_type_changed_user_data\.h', # pylint: disable=line-too-long
372 r'^chrome/browser/browser_switcher/',
373 r'^chrome/browser/chromeos/',
374 r'^chrome/browser/media/router/providers/cast/',
375 r'^chrome/brwoser/sessions/session_restore\.cc',
376 r'^chrome/browser/supervised_user/',
377 r'^chrome/browser/ui/',
378 r'^chromecast/external_mojo/external_service_support/',
379 r'^components/captive_portal/content/captive_portal_service\.h',
380 r'^components/keyed_service/core/keyed_service_shutdown_notifier\.h',
381 r'^components/media_router/browser/',
382 r'^components/ntp_tils/custom_links_manager_impl\.h',
383 r'^components/password_manager/core/browser/hash_password_manager\.h',
384 r'^components/suggestions/suggestions_service\.h',
385 r'^components/sync_device_info/',
386 r'^components/sync_sessions/session_sync_service_impl\.h',
387 r'^components/zoom/zoom_event_manager\.h',
388 r'^content/browser/host_zoom_map_impl\.h',
389 r'^content/browser/network_service_instance_impl\.h',
390 r'^content/browser/rendeer_host/render_process_host_impl\.cc',
391 r'^extensions/test/extension_test_notification_observer\.h',
392 r'^ios/chrome/browser/tabs/tab_parenting_global_observer\.h',
393 r'^ios/net/cookies/cookie_store_ios\.h',
394 r'^net/cookies/cookie_monster_change_dispatcher\.h',
395 r'^remoting/signaling/messaging_client\.h',
396 r'^services/device/battery/battery_status_service\.h',
397 r'^services/device/geolocation/',
398 r'^weblayer/browser/i18n_util\.cc',
399 r'^weblayer/public/cookie_manager\.h',
400))
401
Daniel Bratell609102be2019-03-27 20:53:21402# Format: Sequence of tuples containing:
403# * String pattern or, if starting with a slash, a regular expression.
404# * Sequence of strings to show when the pattern matches.
405# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
406# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59407_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20408 (
Peter Kasting94a56c42019-10-25 21:54:04409 r'/\busing namespace ',
410 (
411 'Using directives ("using namespace x") are banned by the Google Style',
412 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
413 'Explicitly qualify symbols or use using declarations ("using x::foo").',
414 ),
415 True,
416 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
417 ),
Antonio Gomes07300d02019-03-13 20:59:57418 # Make sure that gtest's FRIEND_TEST() macro is not used; the
419 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
420 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53421 (
[email protected]23e6cbc2012-06-16 18:51:20422 'FRIEND_TEST(',
423 (
[email protected]e3c945502012-06-26 20:01:49424 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20425 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
426 ),
427 False,
[email protected]7345da02012-11-27 14:31:49428 (),
[email protected]23e6cbc2012-06-16 18:51:20429 ),
430 (
tomhudsone2c14d552016-05-26 17:07:46431 'setMatrixClip',
432 (
433 'Overriding setMatrixClip() is prohibited; ',
434 'the base function is deprecated. ',
435 ),
436 True,
437 (),
438 ),
439 (
[email protected]52657f62013-05-20 05:30:31440 'SkRefPtr',
441 (
442 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22443 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31444 ),
445 True,
446 (),
447 ),
448 (
449 'SkAutoRef',
450 (
451 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22452 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31453 ),
454 True,
455 (),
456 ),
457 (
458 'SkAutoTUnref',
459 (
460 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22461 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31462 ),
463 True,
464 (),
465 ),
466 (
467 'SkAutoUnref',
468 (
469 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
470 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22471 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31472 ),
473 True,
474 (),
475 ),
[email protected]d89eec82013-12-03 14:10:59476 (
477 r'/HANDLE_EINTR\(.*close',
478 (
479 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
480 'descriptor will be closed, and it is incorrect to retry the close.',
481 'Either call close directly and ignore its return value, or wrap close',
482 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
483 ),
484 True,
485 (),
486 ),
487 (
488 r'/IGNORE_EINTR\((?!.*close)',
489 (
490 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
491 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
492 ),
493 True,
494 (
495 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04496 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
497 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59498 ),
499 ),
[email protected]ec5b3f02014-04-04 18:43:43500 (
501 r'/v8::Extension\(',
502 (
503 'Do not introduce new v8::Extensions into the code base, use',
504 'gin::Wrappable instead. See http://crbug.com/334679',
505 ),
506 True,
[email protected]f55c90ee62014-04-12 00:50:03507 (
Egor Paskoce145c42018-09-28 19:31:04508 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03509 ),
[email protected]ec5b3f02014-04-04 18:43:43510 ),
skyostilf9469f72015-04-20 10:38:52511 (
jame2d1a952016-04-02 00:27:10512 '#pragma comment(lib,',
513 (
514 'Specify libraries to link with in build files and not in the source.',
515 ),
516 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41517 (
tzik3f295992018-12-04 20:32:23518 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04519 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41520 ),
jame2d1a952016-04-02 00:27:10521 ),
fdorayc4ac18d2017-05-01 21:39:59522 (
Gabriel Charette7cc6c432018-04-25 20:52:02523 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59524 (
525 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
526 ),
527 False,
528 (),
529 ),
530 (
Gabriel Charette7cc6c432018-04-25 20:52:02531 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59532 (
533 'Consider using THREAD_CHECKER macros instead of the class directly.',
534 ),
535 False,
536 (),
537 ),
dbeamb6f4fde2017-06-15 04:03:06538 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06539 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
540 (
541 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
542 'deprecated (http://crbug.com/634507). Please avoid converting away',
543 'from the Time types in Chromium code, especially if any math is',
544 'being done on time values. For interfacing with platform/library',
545 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
546 'type converter methods instead. For faking TimeXXX values (for unit',
547 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
548 'other use cases, please contact base/time/OWNERS.',
549 ),
550 False,
551 (),
552 ),
553 (
dbeamb6f4fde2017-06-15 04:03:06554 'CallJavascriptFunctionUnsafe',
555 (
556 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
557 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
558 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
559 ),
560 False,
561 (
Egor Paskoce145c42018-09-28 19:31:04562 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
563 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
564 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06565 ),
566 ),
dskiba1474c2bfd62017-07-20 02:19:24567 (
568 'leveldb::DB::Open',
569 (
570 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
571 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
572 "Chrome's tracing, making their memory usage visible.",
573 ),
574 True,
575 (
576 r'^third_party/leveldatabase/.*\.(cc|h)$',
577 ),
Gabriel Charette0592c3a2017-07-26 12:02:04578 ),
579 (
Chris Mumfordc38afb62017-10-09 17:55:08580 'leveldb::NewMemEnv',
581 (
582 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58583 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
584 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08585 ),
586 True,
587 (
588 r'^third_party/leveldatabase/.*\.(cc|h)$',
589 ),
590 ),
591 (
Gabriel Charetted9839bc2017-07-29 14:17:47592 'RunLoop::QuitCurrent',
593 (
Robert Liao64b7ab22017-08-04 23:03:43594 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
595 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47596 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41597 False,
Gabriel Charetted9839bc2017-07-29 14:17:47598 (),
Gabriel Charettea44975052017-08-21 23:14:04599 ),
600 (
601 'base::ScopedMockTimeMessageLoopTaskRunner',
602 (
Gabriel Charette87cc1af2018-04-25 20:52:51603 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11604 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51605 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
606 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
607 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04608 ),
Gabriel Charette87cc1af2018-04-25 20:52:51609 False,
Gabriel Charettea44975052017-08-21 23:14:04610 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57611 ),
612 (
Dave Tapuska98199b612019-07-10 13:30:44613 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57614 (
615 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02616 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57617 ),
618 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16619 # Abseil's benchmarks never linked into chrome.
620 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38621 ),
622 (
Peter Kasting991618a62019-06-17 22:00:09623 r'/\bstd::stoi\b',
624 (
625 'std::stoi uses exceptions to communicate results. ',
626 'Use base::StringToInt() instead.',
627 ),
628 True,
629 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
630 ),
631 (
632 r'/\bstd::stol\b',
633 (
634 'std::stol uses exceptions to communicate results. ',
635 'Use base::StringToInt() instead.',
636 ),
637 True,
638 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
639 ),
640 (
641 r'/\bstd::stoul\b',
642 (
643 'std::stoul uses exceptions to communicate results. ',
644 'Use base::StringToUint() instead.',
645 ),
646 True,
647 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
648 ),
649 (
650 r'/\bstd::stoll\b',
651 (
652 'std::stoll uses exceptions to communicate results. ',
653 'Use base::StringToInt64() instead.',
654 ),
655 True,
656 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
657 ),
658 (
659 r'/\bstd::stoull\b',
660 (
661 'std::stoull uses exceptions to communicate results. ',
662 'Use base::StringToUint64() instead.',
663 ),
664 True,
665 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
666 ),
667 (
668 r'/\bstd::stof\b',
669 (
670 'std::stof uses exceptions to communicate results. ',
671 'For locale-independent values, e.g. reading numbers from disk',
672 'profiles, use base::StringToDouble().',
673 'For user-visible values, parse using ICU.',
674 ),
675 True,
676 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
677 ),
678 (
679 r'/\bstd::stod\b',
680 (
681 'std::stod uses exceptions to communicate results. ',
682 'For locale-independent values, e.g. reading numbers from disk',
683 'profiles, use base::StringToDouble().',
684 'For user-visible values, parse using ICU.',
685 ),
686 True,
687 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
688 ),
689 (
690 r'/\bstd::stold\b',
691 (
692 'std::stold uses exceptions to communicate results. ',
693 'For locale-independent values, e.g. reading numbers from disk',
694 'profiles, use base::StringToDouble().',
695 'For user-visible values, parse using ICU.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
699 ),
700 (
Daniel Bratell69334cc2019-03-26 11:07:45701 r'/\bstd::to_string\b',
702 (
703 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09704 'For locale-independent strings, e.g. writing numbers to disk',
705 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45706 'For user-visible strings, use base::FormatNumber() and',
707 'the related functions in base/i18n/number_formatting.h.',
708 ),
Peter Kasting991618a62019-06-17 22:00:09709 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21710 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45711 ),
712 (
713 r'/\bstd::shared_ptr\b',
714 (
715 'std::shared_ptr should not be used. Use scoped_refptr instead.',
716 ),
717 True,
Ulan Degenbaev947043882021-02-10 14:02:31718 [
719 # Needed for interop with third-party library.
720 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57721 'array_buffer_contents\.(cc|h)',
Ulan Degenbaev947043882021-02-10 14:02:31722 'gin/array_buffer.cc',
723 'gin/array_buffer.h',
Alex Chau9eb03cdd52020-07-13 21:04:57724 'chrome/services/sharing/nearby/',
725 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21726 ),
727 (
Peter Kasting991618a62019-06-17 22:00:09728 r'/\bstd::weak_ptr\b',
729 (
730 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
731 ),
732 True,
733 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
734 ),
735 (
Daniel Bratell609102be2019-03-27 20:53:21736 r'/\blong long\b',
737 (
738 'long long is banned. Use stdint.h if you need a 64 bit number.',
739 ),
740 False, # Only a warning since it is already used.
741 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
742 ),
743 (
744 r'/\bstd::bind\b',
745 (
746 'std::bind is banned because of lifetime risks.',
747 'Use base::BindOnce or base::BindRepeating instead.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
751 ),
752 (
753 r'/\b#include <chrono>\b',
754 (
755 '<chrono> overlaps with Time APIs in base. Keep using',
756 'base classes.',
757 ),
758 True,
759 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
760 ),
761 (
762 r'/\b#include <exception>\b',
763 (
764 'Exceptions are banned and disabled in Chromium.',
765 ),
766 True,
767 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
768 ),
769 (
770 r'/\bstd::function\b',
771 (
772 'std::function is banned. Instead use base::Callback which directly',
773 'supports Chromium\'s weak pointers, ref counting and more.',
774 ),
Peter Kasting991618a62019-06-17 22:00:09775 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21776 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
777 ),
778 (
779 r'/\b#include <random>\b',
780 (
781 'Do not use any random number engines from <random>. Instead',
782 'use base::RandomBitGenerator.',
783 ),
784 True,
785 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
786 ),
787 (
Tom Andersona95e12042020-09-09 23:08:00788 r'/\b#include <X11/',
789 (
790 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
791 ),
792 True,
793 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
794 ),
795 (
Daniel Bratell609102be2019-03-27 20:53:21796 r'/\bstd::ratio\b',
797 (
798 'std::ratio is banned by the Google Style Guide.',
799 ),
800 True,
801 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45802 ),
803 (
Francois Doray43670e32017-09-27 12:40:38804 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
805 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
806 (
807 'Use the new API in base/threading/thread_restrictions.h.',
808 ),
Gabriel Charette04b138f2018-08-06 00:03:22809 False,
Francois Doray43670e32017-09-27 12:40:38810 (),
811 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38812 (
danakj7a2b7082019-05-21 21:13:51813 r'/\bbase::Bind\(',
814 (
815 'Please use base::Bind{Once,Repeating} instead',
816 'of base::Bind. (crbug.com/714018)',
817 ),
818 False,
Erik Staaba737d7602019-11-25 18:41:07819 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51820 ),
821 (
822 r'/\bbase::Callback[<:]',
823 (
824 'Please use base::{Once,Repeating}Callback instead',
825 'of base::Callback. (crbug.com/714018)',
826 ),
827 False,
Erik Staaba737d7602019-11-25 18:41:07828 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51829 ),
830 (
831 r'/\bbase::Closure\b',
832 (
833 'Please use base::{Once,Repeating}Closure instead',
834 'of base::Closure. (crbug.com/714018)',
835 ),
836 False,
Erik Staaba737d7602019-11-25 18:41:07837 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51838 ),
839 (
Alex Turnerb3ea38c2020-11-25 18:03:07840 r'/\bbase::CancelableCallback[<:]',
841 (
842 'Please use base::Cancelable{Once,Repeating}Callback instead',
843 'of base::CancelableCallback. (crbug.com/714018)',
844 ),
845 False,
846 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
847 ),
848 (
849 r'/\bbase::CancelableClosure\b',
850 (
851 'Please use base::Cancelable{Once,Repeating}Closure instead',
852 'of base::CancelableClosure. (crbug.com/714018)',
853 ),
854 False,
855 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
856 ),
857 (
Alexander Cooper46a92712021-01-30 00:00:20858 r'/\bbase::CallbackList<',
859 (
860 'Please use base::{Once,Repeating}CallbackList instead',
861 'of base::CallbackList. (crbug.com/1113007)'
862 ),
863 False,
864 (_NOT_CONVERTED_TO_MODERN_CALLBACK_LIST,),
865 ),
866 (
Michael Giuffrida7f93d6922019-04-19 14:39:58867 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19868 (
869 'RunMessageLoop is deprecated, use RunLoop instead.',
870 ),
871 False,
872 (),
873 ),
874 (
Dave Tapuska98199b612019-07-10 13:30:44875 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19876 (
877 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
878 ),
879 False,
880 (),
881 ),
882 (
Dave Tapuska98199b612019-07-10 13:30:44883 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19884 (
885 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
886 "if you're convinced you need this.",
887 ),
888 False,
889 (),
890 ),
891 (
Dave Tapuska98199b612019-07-10 13:30:44892 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19893 (
894 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04895 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19896 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
897 'async events instead of flushing threads.',
898 ),
899 False,
900 (),
901 ),
902 (
903 r'MessageLoopRunner',
904 (
905 'MessageLoopRunner is deprecated, use RunLoop instead.',
906 ),
907 False,
908 (),
909 ),
910 (
Dave Tapuska98199b612019-07-10 13:30:44911 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19912 (
913 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
914 "gab@ if you found a use case where this is the only solution.",
915 ),
916 False,
917 (),
918 ),
919 (
Victor Costane48a2e82019-03-15 22:02:34920 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16921 (
Victor Costane48a2e82019-03-15 22:02:34922 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16923 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
924 ),
925 True,
926 (
927 r'^sql/initialization\.(cc|h)$',
928 r'^third_party/sqlite/.*\.(c|cc|h)$',
929 ),
930 ),
Matt Menke7f520a82018-03-28 21:38:37931 (
Dave Tapuska98199b612019-07-10 13:30:44932 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47933 (
934 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
935 'base::RandomShuffle instead.'
936 ),
937 True,
938 (),
939 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24940 (
941 'ios/web/public/test/http_server',
942 (
943 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
944 ),
945 False,
946 (),
947 ),
Robert Liao764c9492019-01-24 18:46:28948 (
949 'GetAddressOf',
950 (
951 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53952 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11953 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53954 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28955 ),
956 True,
957 (),
958 ),
Antonio Gomes07300d02019-03-13 20:59:57959 (
Ben Lewisa9514602019-04-29 17:53:05960 'SHFileOperation',
961 (
962 'SHFileOperation was deprecated in Windows Vista, and there are less ',
963 'complex functions to achieve the same goals. Use IFileOperation for ',
964 'any esoteric actions instead.'
965 ),
966 True,
967 (),
968 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18969 (
Cliff Smolinsky81951642019-04-30 21:39:51970 'StringFromGUID2',
971 (
972 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24973 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51974 ),
975 True,
976 (
977 r'/base/win/win_util_unittest.cc'
978 ),
979 ),
980 (
981 'StringFromCLSID',
982 (
983 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24984 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51985 ),
986 True,
987 (
988 r'/base/win/win_util_unittest.cc'
989 ),
990 ),
991 (
Avi Drissman7382afa02019-04-29 23:27:13992 'kCFAllocatorNull',
993 (
994 'The use of kCFAllocatorNull with the NoCopy creation of ',
995 'CoreFoundation types is prohibited.',
996 ),
997 True,
998 (),
999 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291000 (
1001 'mojo::ConvertTo',
1002 (
1003 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1004 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1005 'StringTraits if you would like to convert between custom types and',
1006 'the wire format of mojom types.'
1007 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221008 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291009 (
Wezf89dec092019-09-11 19:38:331010 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1011 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291012 r'^third_party/blink/.*\.(cc|h)$',
1013 r'^content/renderer/.*\.(cc|h)$',
1014 ),
1015 ),
Robert Liao1d78df52019-11-11 20:02:011016 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161017 'GetInterfaceProvider',
1018 (
1019 'InterfaceProvider is deprecated.',
1020 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1021 'or Platform::GetBrowserInterfaceBroker.'
1022 ),
1023 False,
1024 (),
1025 ),
1026 (
Robert Liao1d78df52019-11-11 20:02:011027 'CComPtr',
1028 (
1029 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1030 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1031 'details.'
1032 ),
1033 False,
1034 (),
1035 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201036 (
1037 r'/\b(IFACE|STD)METHOD_?\(',
1038 (
1039 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1040 'Instead, always use IFACEMETHODIMP in the declaration.'
1041 ),
1042 False,
1043 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1044 ),
Allen Bauer53b43fb12020-03-12 17:21:471045 (
1046 'set_owned_by_client',
1047 (
1048 'set_owned_by_client is deprecated.',
1049 'views::View already owns the child views by default. This introduces ',
1050 'a competing ownership model which makes the code difficult to reason ',
1051 'about. See http://crbug.com/1044687 for more details.'
1052 ),
1053 False,
1054 (),
1055 ),
Eric Secklerbe6f48d2020-05-06 18:09:121056 (
1057 r'/\bTRACE_EVENT_ASYNC_',
1058 (
1059 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1060 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1061 ),
1062 False,
1063 (
1064 r'^base/trace_event/.*',
1065 r'^base/tracing/.*',
1066 ),
1067 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261068 (
1069 r'/\bScopedObserver',
1070 (
1071 'ScopedObserver is deprecated.',
1072 'Please use base::ScopedObservation for observing a single source,',
1073 'or base::ScopedMultiSourceObservation for observing multple sources',
1074 ),
1075 False,
1076 (),
1077 ),
[email protected]127f18ec2012-06-16 05:05:591078)
1079
Mario Sanchez Prada2472cab2019-09-18 10:58:311080# Format: Sequence of tuples containing:
1081# * String pattern or, if starting with a slash, a regular expression.
1082# * Sequence of strings to show when the pattern matches.
1083_DEPRECATED_MOJO_TYPES = (
1084 (
1085 r'/\bmojo::AssociatedBinding\b',
1086 (
1087 'mojo::AssociatedBinding<Interface> is deprecated.',
1088 'Use mojo::AssociatedReceiver<Interface> instead.',
1089 ),
1090 ),
1091 (
1092 r'/\bmojo::AssociatedBindingSet\b',
1093 (
1094 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1095 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1096 ),
1097 ),
1098 (
1099 r'/\bmojo::AssociatedInterfacePtr\b',
1100 (
1101 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1102 'Use mojo::AssociatedRemote<Interface> instead.',
1103 ),
1104 ),
1105 (
1106 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1107 (
1108 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1109 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1110 ),
1111 ),
1112 (
1113 r'/\bmojo::AssociatedInterfaceRequest\b',
1114 (
1115 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1116 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1117 ),
1118 ),
1119 (
1120 r'/\bmojo::Binding\b',
1121 (
1122 'mojo::Binding<Interface> is deprecated.',
1123 'Use mojo::Receiver<Interface> instead.',
1124 ),
1125 ),
1126 (
1127 r'/\bmojo::BindingSet\b',
1128 (
1129 'mojo::BindingSet<Interface> is deprecated.',
1130 'Use mojo::ReceiverSet<Interface> instead.',
1131 ),
1132 ),
1133 (
1134 r'/\bmojo::InterfacePtr\b',
1135 (
1136 'mojo::InterfacePtr<Interface> is deprecated.',
1137 'Use mojo::Remote<Interface> instead.',
1138 ),
1139 ),
1140 (
1141 r'/\bmojo::InterfacePtrInfo\b',
1142 (
1143 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1144 'Use mojo::PendingRemote<Interface> instead.',
1145 ),
1146 ),
1147 (
1148 r'/\bmojo::InterfaceRequest\b',
1149 (
1150 'mojo::InterfaceRequest<Interface> is deprecated.',
1151 'Use mojo::PendingReceiver<Interface> instead.',
1152 ),
1153 ),
1154 (
1155 r'/\bmojo::MakeRequest\b',
1156 (
1157 'mojo::MakeRequest is deprecated.',
1158 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1159 ),
1160 ),
1161 (
1162 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1163 (
1164 'mojo::MakeRequest is deprecated.',
1165 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181166 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311167 ),
1168 ),
1169 (
1170 r'/\bmojo::MakeStrongBinding\b',
1171 (
1172 'mojo::MakeStrongBinding is deprecated.',
1173 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1174 'mojo::MakeSelfOwnedReceiver() instead.',
1175 ),
1176 ),
1177 (
1178 r'/\bmojo::MakeStrongAssociatedBinding\b',
1179 (
1180 'mojo::MakeStrongAssociatedBinding is deprecated.',
1181 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1182 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1183 ),
1184 ),
1185 (
Gyuyoung Kim4952ba62020-07-07 07:33:441186 r'/\bmojo::StrongAssociatedBinding\b',
1187 (
1188 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1189 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1190 ),
1191 ),
1192 (
1193 r'/\bmojo::StrongBinding\b',
1194 (
1195 'mojo::StrongBinding<Interface> is deprecated.',
1196 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1197 ),
1198 ),
1199 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311200 r'/\bmojo::StrongAssociatedBindingSet\b',
1201 (
1202 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1203 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1204 ),
1205 ),
1206 (
1207 r'/\bmojo::StrongBindingSet\b',
1208 (
1209 'mojo::StrongBindingSet<Interface> is deprecated.',
1210 'Use mojo::UniqueReceiverSet<Interface> instead.',
1211 ),
1212 ),
1213)
wnwenbdc444e2016-05-25 13:44:151214
mlamouria82272622014-09-16 18:45:041215_IPC_ENUM_TRAITS_DEPRECATED = (
1216 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501217 'See http://www.chromium.org/Home/chromium-security/education/'
1218 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041219
Stephen Martinis97a394142018-06-07 23:06:051220_LONG_PATH_ERROR = (
1221 'Some files included in this CL have file names that are too long (> 200'
1222 ' characters). If committed, these files will cause issues on Windows. See'
1223 ' https://crbug.com/612667 for more details.'
1224)
1225
Shenghua Zhangbfaa38b82017-11-16 21:58:021226_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041227 r".*[\\/]BuildHooksAndroidImpl\.java",
1228 r".*[\\/]LicenseContentProvider\.java",
1229 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281230 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021231]
[email protected]127f18ec2012-06-16 05:05:591232
Mohamed Heikald048240a2019-11-12 16:57:371233# List of image extensions that are used as resources in chromium.
1234_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1235
Sean Kau46e29bc2017-08-28 16:31:161236# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401237_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041238 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401239 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041240 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1241 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041242 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431243 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161244]
1245
1246
[email protected]b00342e7f2013-03-26 16:21:541247_VALID_OS_MACROS = (
1248 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081249 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541250 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441251 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121252 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541253 'OS_BSD',
1254 'OS_CAT', # For testing.
1255 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041256 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541257 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371258 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541259 'OS_IOS',
1260 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441261 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541262 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211263 'OS_NACL_NONSFI',
1264 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121265 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541266 'OS_OPENBSD',
1267 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371268 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541269 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541270 'OS_WIN',
1271)
1272
1273
Andrew Grieveb773bad2020-06-05 18:00:381274# These are not checked on the public chromium-presubmit trybot.
1275# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041276# checkouts.
agrievef32bcc72016-04-04 14:57:401277_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381278 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381279]
1280
1281
1282_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041283 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361284 'base/android/jni_generator/jni_generator.pydeps',
1285 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361286 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041287 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361288 'build/android/gyp/aar.pydeps',
1289 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271290 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361291 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381292 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361293 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021294 'build/android/gyp/bytecode_rewriter.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111295 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361296 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361297 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361298 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111299 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041300 'build/android/gyp/create_app_bundle_apks.pydeps',
1301 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361302 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121303 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091304 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221305 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001306 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'build/android/gyp/desugar.pydeps',
1308 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421309 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041310 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361312 'build/android/gyp/filter_zip.pydeps',
1313 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361314 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361315 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581316 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141318 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261319 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011320 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041321 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/merge_manifest.pydeps',
1324 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221325 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461327 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241328 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461330 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561331 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/incremental_install/generate_android_manifest.pydeps',
1333 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041334 'build/android/resource_sizes.pydeps',
1335 'build/android/test_runner.pydeps',
1336 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361337 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321339 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271340 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1341 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001342 'components/cronet/tools/generate_javadoc.pydeps',
1343 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381344 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001345 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381346 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041347 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181348 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041349 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421350 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1351 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131352 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061353 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221354 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401355]
1356
wnwenbdc444e2016-05-25 13:44:151357
agrievef32bcc72016-04-04 14:57:401358_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1359
1360
Eric Boren6fd2b932018-01-25 15:05:081361# Bypass the AUTHORS check for these accounts.
1362_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591363 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451364 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591365 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521366 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071367 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041368 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271369 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041370 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301371 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081372
1373
Daniel Bratell65b033262019-04-23 08:17:061374def _IsCPlusPlusFile(input_api, file_path):
1375 """Returns True if this file contains C++-like code (and not Python,
1376 Go, Java, MarkDown, ...)"""
1377
1378 ext = input_api.os_path.splitext(file_path)[1]
1379 # This list is compatible with CppChecker.IsCppFile but we should
1380 # consider adding ".c" to it. If we do that we can use this function
1381 # at more places in the code.
1382 return ext in (
1383 '.h',
1384 '.cc',
1385 '.cpp',
1386 '.m',
1387 '.mm',
1388 )
1389
1390def _IsCPlusPlusHeaderFile(input_api, file_path):
1391 return input_api.os_path.splitext(file_path)[1] == ".h"
1392
1393
1394def _IsJavaFile(input_api, file_path):
1395 return input_api.os_path.splitext(file_path)[1] == ".java"
1396
1397
1398def _IsProtoFile(input_api, file_path):
1399 return input_api.os_path.splitext(file_path)[1] == ".proto"
1400
Mohamed Heikal5e5b7922020-10-29 18:57:591401
1402def CheckNoUpstreamDepsOnClank(input_api, output_api):
1403 """Prevent additions of dependencies from the upstream repo on //clank."""
1404 # clank can depend on clank
1405 if input_api.change.RepositoryRoot().endswith('clank'):
1406 return []
1407 build_file_patterns = [
1408 r'(.+/)?BUILD\.gn',
1409 r'.+\.gni',
1410 ]
1411 excluded_files = [
1412 r'build[/\\]config[/\\]android[/\\]config\.gni'
1413 ]
1414 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1415
1416 error_message = 'Disallowed import on //clank in an upstream build file:'
1417
1418 def FilterFile(affected_file):
1419 return input_api.FilterSourceFile(
1420 affected_file,
1421 files_to_check=build_file_patterns,
1422 files_to_skip=excluded_files)
1423
1424 problems = []
1425 for f in input_api.AffectedSourceFiles(FilterFile):
1426 local_path = f.LocalPath()
1427 for line_number, line in f.ChangedContents():
1428 if (bad_pattern.search(line)):
1429 problems.append(
1430 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1431 if problems:
1432 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1433 else:
1434 return []
1435
1436
Saagar Sanghavifceeaae2020-08-12 16:40:361437def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191438 """Attempts to prevent use of functions intended only for testing in
1439 non-testing code. For now this is just a best-effort implementation
1440 that ignores header files and may have some false positives. A
1441 better implementation would probably need a proper C++ parser.
1442 """
1443 # We only scan .cc files and the like, as the declaration of
1444 # for-testing functions in header files are hard to distinguish from
1445 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491446 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191447
jochenc0d4808c2015-07-27 09:25:421448 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191449 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091450 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131451 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191452 exclusion_pattern = input_api.re.compile(
1453 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1454 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131455 # Avoid a false positive in this case, where the method name, the ::, and
1456 # the closing { are all on different lines due to line wrapping.
1457 # HelperClassForTesting::
1458 # HelperClassForTesting(
1459 # args)
1460 # : member(0) {}
1461 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191462
1463 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441464 files_to_skip = (_EXCLUDED_PATHS +
1465 _TEST_CODE_EXCLUDED_PATHS +
1466 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191467 return input_api.FilterSourceFile(
1468 affected_file,
James Cook24a504192020-07-23 00:08:441469 files_to_check=file_inclusion_pattern,
1470 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191471
1472 problems = []
1473 for f in input_api.AffectedSourceFiles(FilterFile):
1474 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131475 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241476 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031477 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461478 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131479 not exclusion_pattern.search(line) and
1480 not allowlist_pattern.search(line) and
1481 not in_method_defn):
[email protected]55459852011-08-10 15:17:191482 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031483 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131484 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191485
1486 if problems:
[email protected]f7051d52013-04-02 18:31:421487 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031488 else:
1489 return []
[email protected]55459852011-08-10 15:17:191490
1491
Saagar Sanghavifceeaae2020-08-12 16:40:361492def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231493 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591494 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231495 """
1496 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1497 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1498 name_pattern = r'ForTest(s|ing)?'
1499 # Describes an occurrence of "ForTest*" inside a // comment.
1500 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501501 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551502 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231503 # Catch calls.
1504 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1505 # Ignore definitions. (Comments are ignored separately.)
1506 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1507
1508 problems = []
1509 sources = lambda x: input_api.FilterSourceFile(
1510 x,
James Cook24a504192020-07-23 00:08:441511 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1512 + input_api.DEFAULT_FILES_TO_SKIP),
1513 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231514 )
1515 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1516 local_path = f.LocalPath()
1517 is_inside_javadoc = False
1518 for line_number, line in f.ChangedContents():
1519 if is_inside_javadoc and javadoc_end_re.search(line):
1520 is_inside_javadoc = False
1521 if not is_inside_javadoc and javadoc_start_re.search(line):
1522 is_inside_javadoc = True
1523 if is_inside_javadoc:
1524 continue
1525 if (inclusion_re.search(line) and
1526 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501527 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231528 not exclusion_re.search(line)):
1529 problems.append(
1530 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1531
1532 if problems:
1533 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1534 else:
1535 return []
1536
1537
Saagar Sanghavifceeaae2020-08-12 16:40:361538def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541539 """Checks to make sure no .h files include <iostream>."""
1540 files = []
1541 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1542 input_api.re.MULTILINE)
1543 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1544 if not f.LocalPath().endswith('.h'):
1545 continue
1546 contents = input_api.ReadFile(f)
1547 if pattern.search(contents):
1548 files.append(f)
1549
1550 if len(files):
yolandyandaabc6d2016-04-18 18:29:391551 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061552 'Do not #include <iostream> in header files, since it inserts static '
1553 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541554 '#include <ostream>. See http://crbug.com/94794',
1555 files) ]
1556 return []
1557
Danil Chapovalov3518f362018-08-11 16:13:431558def _CheckNoStrCatRedefines(input_api, output_api):
1559 """Checks no windows headers with StrCat redefined are included directly."""
1560 files = []
1561 pattern_deny = input_api.re.compile(
1562 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1563 input_api.re.MULTILINE)
1564 pattern_allow = input_api.re.compile(
1565 r'^#include\s"base/win/windows_defines.inc"',
1566 input_api.re.MULTILINE)
1567 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1568 contents = input_api.ReadFile(f)
1569 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1570 files.append(f.LocalPath())
1571
1572 if len(files):
1573 return [output_api.PresubmitError(
1574 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1575 'directly since they pollute code with StrCat macro. Instead, '
1576 'include matching header from base/win. See http://crbug.com/856536',
1577 files) ]
1578 return []
1579
[email protected]10689ca2011-09-02 02:31:541580
Saagar Sanghavifceeaae2020-08-12 16:40:361581def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521582 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181583 problems = []
1584 for f in input_api.AffectedFiles():
1585 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1586 continue
1587
1588 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041589 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181590 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1591
1592 if not problems:
1593 return []
1594 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1595 '\n'.join(problems))]
1596
Saagar Sanghavifceeaae2020-08-12 16:40:361597def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341598 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1599
1600 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1601 instead of DISABLED_. To filter false positives, reports are only generated
1602 if a corresponding MAYBE_ line exists.
1603 """
1604 problems = []
1605
1606 # The following two patterns are looked for in tandem - is a test labeled
1607 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1608 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1609 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1610
1611 # This is for the case that a test is disabled on all platforms.
1612 full_disable_pattern = input_api.re.compile(
1613 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1614 input_api.re.MULTILINE)
1615
Katie Df13948e2018-09-25 07:33:441616 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341617 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1618 continue
1619
1620 # Search for MABYE_, DISABLE_ pairs.
1621 disable_lines = {} # Maps of test name to line number.
1622 maybe_lines = {}
1623 for line_num, line in f.ChangedContents():
1624 disable_match = disable_pattern.search(line)
1625 if disable_match:
1626 disable_lines[disable_match.group(1)] = line_num
1627 maybe_match = maybe_pattern.search(line)
1628 if maybe_match:
1629 maybe_lines[maybe_match.group(1)] = line_num
1630
1631 # Search for DISABLE_ occurrences within a TEST() macro.
1632 disable_tests = set(disable_lines.keys())
1633 maybe_tests = set(maybe_lines.keys())
1634 for test in disable_tests.intersection(maybe_tests):
1635 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1636
1637 contents = input_api.ReadFile(f)
1638 full_disable_match = full_disable_pattern.search(contents)
1639 if full_disable_match:
1640 problems.append(' %s' % f.LocalPath())
1641
1642 if not problems:
1643 return []
1644 return [
1645 output_api.PresubmitPromptWarning(
1646 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1647 '\n'.join(problems))
1648 ]
1649
[email protected]72df4e782012-06-21 16:28:181650
Saagar Sanghavifceeaae2020-08-12 16:40:361651def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571652 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521653 errors = []
Hans Wennborg944479f2020-06-25 21:39:251654 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521655 input_api.re.MULTILINE)
1656 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1657 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1658 continue
1659 for lnum, line in f.ChangedContents():
1660 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171661 errors.append(output_api.PresubmitError(
1662 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571663 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171664 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521665 return errors
1666
1667
Weilun Shia487fad2020-10-28 00:10:341668# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1669# more reliable way. See
1670# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191671
wnwenbdc444e2016-05-25 13:44:151672
Saagar Sanghavifceeaae2020-08-12 16:40:361673def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391674 """Check that FlakyTest annotation is our own instead of the android one"""
1675 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1676 files = []
1677 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1678 if f.LocalPath().endswith('Test.java'):
1679 if pattern.search(input_api.ReadFile(f)):
1680 files.append(f)
1681 if len(files):
1682 return [output_api.PresubmitError(
1683 'Use org.chromium.base.test.util.FlakyTest instead of '
1684 'android.test.FlakyTest',
1685 files)]
1686 return []
mcasasb7440c282015-02-04 14:52:191687
wnwenbdc444e2016-05-25 13:44:151688
Saagar Sanghavifceeaae2020-08-12 16:40:361689def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221690 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271691 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221692 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201693 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571694 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341695 '/win/' in f.LocalPath() or
1696 'chrome_elf' in f.LocalPath() or
1697 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201698 continue
[email protected]8ea5d4b2011-09-13 21:49:221699
[email protected]a11dbe9b2012-08-07 01:32:581700 allowWString = False
[email protected]b5c24292011-11-28 14:38:201701 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581702 if 'presubmit: allow wstring' in line:
1703 allowWString = True
1704 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271705 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581706 allowWString = False
1707 else:
1708 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221709
[email protected]55463aa62011-10-12 00:48:271710 if not problems:
1711 return []
1712 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581713 ' If you are calling a cross-platform API that accepts a wstring, '
1714 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271715 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221716
1717
Saagar Sanghavifceeaae2020-08-12 16:40:361718def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441719 """Make sure .DEPS.git is never modified manually."""
1720 if any(f.LocalPath().endswith('.DEPS.git') for f in
1721 input_api.AffectedFiles()):
1722 return [output_api.PresubmitError(
1723 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1724 'automated system based on what\'s in DEPS and your changes will be\n'
1725 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501726 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1727 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441728 'for more information')]
1729 return []
1730
1731
Saagar Sanghavifceeaae2020-08-12 16:40:361732def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471733 """Checks that DEPS file deps are from allowed_hosts."""
1734 # Run only if DEPS file has been modified to annoy fewer bystanders.
1735 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1736 return []
1737 # Outsource work to gclient verify
1738 try:
John Budorickf20c0042019-04-25 23:23:401739 gclient_path = input_api.os_path.join(
1740 input_api.PresubmitLocalPath(),
1741 'third_party', 'depot_tools', 'gclient.py')
1742 input_api.subprocess.check_output(
1743 [input_api.python_executable, gclient_path, 'verify'],
1744 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471745 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201746 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471747 return [output_api.PresubmitError(
1748 'DEPS file must have only git dependencies.',
1749 long_text=error.output)]
1750
1751
Mario Sanchez Prada2472cab2019-09-18 10:58:311752def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1753 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591754 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311755
1756 Returns an string composed of the name of the file, the line number where the
1757 match has been found and the additional text passed as |message| in case the
1758 target type name matches the text inside the line passed as parameter.
1759 """
Peng Huang9c5949a02020-06-11 19:20:541760 result = []
1761
danakjd18e8892020-12-17 17:42:011762 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1763 return result
1764 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541765 return result
1766
Mario Sanchez Prada2472cab2019-09-18 10:58:311767 matched = False
1768 if type_name[0:1] == '/':
1769 regex = type_name[1:]
1770 if input_api.re.search(regex, line):
1771 matched = True
1772 elif type_name in line:
1773 matched = True
1774
Mario Sanchez Prada2472cab2019-09-18 10:58:311775 if matched:
1776 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1777 for message_line in message:
1778 result.append(' %s' % message_line)
1779
1780 return result
1781
1782
Saagar Sanghavifceeaae2020-08-12 16:40:361783def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591784 """Make sure that banned functions are not used."""
1785 warnings = []
1786 errors = []
1787
James Cook24a504192020-07-23 00:08:441788 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151789 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441790 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151791 if input_api.re.match(item, local_path):
1792 return True
1793 return False
1794
Peter K. Lee6c03ccff2019-07-15 14:40:051795 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541796 local_path = affected_file.LocalPath()
1797 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1798 return False
1799 basename = input_api.os_path.basename(local_path)
1800 if 'ios' in basename.split('_'):
1801 return True
1802 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1803 if sep and 'ios' in local_path.split(sep):
1804 return True
1805 return False
1806
wnwenbdc444e2016-05-25 13:44:151807 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311808 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1809 func_name, message)
1810 if problems:
wnwenbdc444e2016-05-25 13:44:151811 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311812 errors.extend(problems)
1813 else:
1814 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151815
Eric Stevensona9a980972017-09-23 00:04:411816 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1817 for f in input_api.AffectedFiles(file_filter=file_filter):
1818 for line_num, line in f.ChangedContents():
1819 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1820 CheckForMatch(f, line_num, line, func_name, message, error)
1821
[email protected]127f18ec2012-06-16 05:05:591822 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1823 for f in input_api.AffectedFiles(file_filter=file_filter):
1824 for line_num, line in f.ChangedContents():
1825 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151826 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591827
Peter K. Lee6c03ccff2019-07-15 14:40:051828 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541829 for line_num, line in f.ChangedContents():
1830 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1831 CheckForMatch(f, line_num, line, func_name, message, error)
1832
Peter K. Lee6c03ccff2019-07-15 14:40:051833 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1834 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1835 for line_num, line in f.ChangedContents():
1836 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1837 CheckForMatch(f, line_num, line, func_name, message, error)
1838
[email protected]127f18ec2012-06-16 05:05:591839 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1840 for f in input_api.AffectedFiles(file_filter=file_filter):
1841 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491842 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441843 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491844 continue
wnwenbdc444e2016-05-25 13:44:151845 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591846
1847 result = []
1848 if (warnings):
1849 result.append(output_api.PresubmitPromptWarning(
1850 'Banned functions were used.\n' + '\n'.join(warnings)))
1851 if (errors):
1852 result.append(output_api.PresubmitError(
1853 'Banned functions were used.\n' + '\n'.join(errors)))
1854 return result
1855
1856
Michael Thiessen44457642020-02-06 00:24:151857def _CheckAndroidNoBannedImports(input_api, output_api):
1858 """Make sure that banned java imports are not used."""
1859 errors = []
1860
1861 def IsException(path, exceptions):
1862 for exception in exceptions:
1863 if (path.startswith(exception)):
1864 return True
1865 return False
1866
1867 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1868 for f in input_api.AffectedFiles(file_filter=file_filter):
1869 for line_num, line in f.ChangedContents():
1870 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1871 if IsException(f.LocalPath(), exceptions):
1872 continue;
1873 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1874 'import ' + import_name, message)
1875 if problems:
1876 errors.extend(problems)
1877 result = []
1878 if (errors):
1879 result.append(output_api.PresubmitError(
1880 'Banned imports were used.\n' + '\n'.join(errors)))
1881 return result
1882
1883
Saagar Sanghavifceeaae2020-08-12 16:40:361884def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311885 """Make sure that old Mojo types are not used."""
1886 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571887 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311888
Mario Sanchez Pradaaab91382019-12-19 08:57:091889 # For any path that is not an "ok" or an "error" path, a warning will be
1890 # raised if deprecated mojo types are found.
1891 ok_paths = ['components/arc']
1892 error_paths = ['third_party/blink', 'content']
1893
Mario Sanchez Prada2472cab2019-09-18 10:58:311894 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1895 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571896 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091897 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311898 continue
1899
1900 for line_num, line in f.ChangedContents():
1901 for func_name, message in _DEPRECATED_MOJO_TYPES:
1902 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1903 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571904
Mario Sanchez Prada2472cab2019-09-18 10:58:311905 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091906 # Raise errors inside |error_paths| and warnings everywhere else.
1907 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571908 errors.extend(problems)
1909 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311910 warnings.extend(problems)
1911
1912 result = []
1913 if (warnings):
1914 result.append(output_api.PresubmitPromptWarning(
1915 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571916 if (errors):
1917 result.append(output_api.PresubmitError(
1918 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311919 return result
1920
1921
Saagar Sanghavifceeaae2020-08-12 16:40:361922def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061923 """Make sure that banned functions are not used."""
1924 files = []
1925 pattern = input_api.re.compile(r'^#pragma\s+once',
1926 input_api.re.MULTILINE)
1927 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1928 if not f.LocalPath().endswith('.h'):
1929 continue
1930 contents = input_api.ReadFile(f)
1931 if pattern.search(contents):
1932 files.append(f)
1933
1934 if files:
1935 return [output_api.PresubmitError(
1936 'Do not use #pragma once in header files.\n'
1937 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1938 files)]
1939 return []
1940
[email protected]127f18ec2012-06-16 05:05:591941
Saagar Sanghavifceeaae2020-08-12 16:40:361942def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121943 """Checks to make sure we don't introduce use of foo ? true : false."""
1944 problems = []
1945 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1946 for f in input_api.AffectedFiles():
1947 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1948 continue
1949
1950 for line_num, line in f.ChangedContents():
1951 if pattern.match(line):
1952 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1953
1954 if not problems:
1955 return []
1956 return [output_api.PresubmitPromptWarning(
1957 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1958 '\n'.join(problems))]
1959
1960
Saagar Sanghavifceeaae2020-08-12 16:40:361961def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281962 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181963 change. Breaking - rules is an error, breaking ! rules is a
1964 warning.
1965 """
mohan.reddyf21db962014-10-16 12:26:471966 import sys
[email protected]55f9f382012-07-31 11:02:181967 # We need to wait until we have an input_api object and use this
1968 # roundabout construct to import checkdeps because this file is
1969 # eval-ed and thus doesn't have __file__.
1970 original_sys_path = sys.path
1971 try:
1972 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471973 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181974 import checkdeps
[email protected]55f9f382012-07-31 11:02:181975 from rules import Rule
1976 finally:
1977 # Restore sys.path to what it was before.
1978 sys.path = original_sys_path
1979
1980 added_includes = []
rhalavati08acd232017-04-03 07:23:281981 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241982 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181983 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061984 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501985 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081986 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061987 elif _IsProtoFile(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_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061990 elif _IsJavaFile(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_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181993
[email protected]26385172013-05-09 23:11:351994 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181995
1996 error_descriptions = []
1997 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281998 error_subjects = set()
1999 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362000
[email protected]55f9f382012-07-31 11:02:182001 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2002 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082003 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182004 description_with_path = '%s\n %s' % (path, rule_description)
2005 if rule_type == Rule.DISALLOW:
2006 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282007 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182008 else:
2009 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282010 warning_subjects.add("#includes")
2011
2012 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2013 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082014 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282015 description_with_path = '%s\n %s' % (path, rule_description)
2016 if rule_type == Rule.DISALLOW:
2017 error_descriptions.append(description_with_path)
2018 error_subjects.add("imports")
2019 else:
2020 warning_descriptions.append(description_with_path)
2021 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182022
Jinsuk Kim5a092672017-10-24 22:42:242023 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022024 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082025 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242026 description_with_path = '%s\n %s' % (path, rule_description)
2027 if rule_type == Rule.DISALLOW:
2028 error_descriptions.append(description_with_path)
2029 error_subjects.add("imports")
2030 else:
2031 warning_descriptions.append(description_with_path)
2032 warning_subjects.add("imports")
2033
[email protected]55f9f382012-07-31 11:02:182034 results = []
2035 if error_descriptions:
2036 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282037 'You added one or more %s that violate checkdeps rules.'
2038 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182039 error_descriptions))
2040 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422041 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282042 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182043 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282044 '%s? See relevant DEPS file(s) for details and contacts.' %
2045 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182046 warning_descriptions))
2047 return results
2048
2049
Saagar Sanghavifceeaae2020-08-12 16:40:362050def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222051 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152052 if input_api.platform == 'win32':
2053 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292054 checkperms_tool = input_api.os_path.join(
2055 input_api.PresubmitLocalPath(),
2056 'tools', 'checkperms', 'checkperms.py')
2057 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472058 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392059 with input_api.CreateTemporaryFile() as file_list:
2060 for f in input_api.AffectedFiles():
2061 # checkperms.py file/directory arguments must be relative to the
2062 # repository.
2063 file_list.write(f.LocalPath() + '\n')
2064 file_list.close()
2065 args += ['--file-list', file_list.name]
2066 try:
2067 input_api.subprocess.check_output(args)
2068 return []
2069 except input_api.subprocess.CalledProcessError as error:
2070 return [output_api.PresubmitError(
2071 'checkperms.py failed:',
2072 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222073
2074
Saagar Sanghavifceeaae2020-08-12 16:40:362075def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492076 """Makes sure we don't include ui/aura/window_property.h
2077 in header files.
2078 """
2079 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2080 errors = []
2081 for f in input_api.AffectedFiles():
2082 if not f.LocalPath().endswith('.h'):
2083 continue
2084 for line_num, line in f.ChangedContents():
2085 if pattern.match(line):
2086 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2087
2088 results = []
2089 if errors:
2090 results.append(output_api.PresubmitError(
2091 'Header files should not include ui/aura/window_property.h', errors))
2092 return results
2093
2094
[email protected]70ca77752012-11-20 03:45:032095def _CheckForVersionControlConflictsInFile(input_api, f):
2096 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2097 errors = []
2098 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162099 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232100 # First-level headers in markdown look a lot like version control
2101 # conflict markers. http://daringfireball.net/projects/markdown/basics
2102 continue
[email protected]70ca77752012-11-20 03:45:032103 if pattern.match(line):
2104 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2105 return errors
2106
2107
Saagar Sanghavifceeaae2020-08-12 16:40:362108def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032109 """Usually this is not intentional and will cause a compile failure."""
2110 errors = []
2111 for f in input_api.AffectedFiles():
2112 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2113
2114 results = []
2115 if errors:
2116 results.append(output_api.PresubmitError(
2117 'Version control conflict markers found, please resolve.', errors))
2118 return results
2119
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202120
Saagar Sanghavifceeaae2020-08-12 16:40:362121def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162122 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2123 errors = []
2124 for f in input_api.AffectedFiles():
2125 for line_num, line in f.ChangedContents():
2126 if pattern.search(line):
2127 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2128
2129 results = []
2130 if errors:
2131 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502132 'Found Google support URL addressed by answer number. Please replace '
2133 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162134 return results
2135
[email protected]70ca77752012-11-20 03:45:032136
Saagar Sanghavifceeaae2020-08-12 16:40:362137def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442138 def FilterFile(affected_file):
2139 """Filter function for use with input_api.AffectedSourceFiles,
2140 below. This filters out everything except non-test files from
2141 top-level directories that generally speaking should not hard-code
2142 service URLs (e.g. src/android_webview/, src/content/ and others).
2143 """
2144 return input_api.FilterSourceFile(
2145 affected_file,
James Cook24a504192020-07-23 00:08:442146 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2147 files_to_skip=(_EXCLUDED_PATHS +
2148 _TEST_CODE_EXCLUDED_PATHS +
2149 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442150
reillyi38965732015-11-16 18:27:332151 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2152 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462153 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2154 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442155 problems = [] # items are (filename, line_number, line)
2156 for f in input_api.AffectedSourceFiles(FilterFile):
2157 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462158 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442159 problems.append((f.LocalPath(), line_num, line))
2160
2161 if problems:
[email protected]f7051d52013-04-02 18:31:422162 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442163 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582164 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442165 [' %s:%d: %s' % (
2166 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032167 else:
2168 return []
[email protected]06e6d0ff2012-12-11 01:36:442169
2170
Saagar Sanghavifceeaae2020-08-12 16:40:362171def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292172 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2173 def FileFilter(affected_file):
2174 """Includes directories known to be Chrome OS only."""
2175 return input_api.FilterSourceFile(
2176 affected_file,
James Cook24a504192020-07-23 00:08:442177 files_to_check=('^ash/',
2178 '^chromeos/', # Top-level src/chromeos.
2179 '/chromeos/', # Any path component.
2180 '^components/arc',
2181 '^components/exo'),
2182 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292183
2184 prefs = []
2185 priority_prefs = []
2186 for f in input_api.AffectedFiles(file_filter=FileFilter):
2187 for line_num, line in f.ChangedContents():
2188 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2189 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2190 prefs.append(' %s' % line)
2191 if input_api.re.search(
2192 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2193 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2194 priority_prefs.append(' %s' % line)
2195
2196 results = []
2197 if (prefs):
2198 results.append(output_api.PresubmitPromptWarning(
2199 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2200 'by browser sync settings. If these prefs should be controlled by OS '
2201 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2202 if (priority_prefs):
2203 results.append(output_api.PresubmitPromptWarning(
2204 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2205 'controlled by browser sync settings. If these prefs should be '
2206 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2207 'instead.\n' + '\n'.join(prefs)))
2208 return results
2209
2210
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492211# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362212def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272213 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312214 The native_client_sdk directory is excluded because it has auto-generated PNG
2215 files for documentation.
[email protected]d2530012013-01-25 16:39:272216 """
[email protected]d2530012013-01-25 16:39:272217 errors = []
James Cook24a504192020-07-23 00:08:442218 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2219 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312220 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442221 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312222 for f in input_api.AffectedFiles(include_deletes=False,
2223 file_filter=file_filter):
2224 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272225
2226 results = []
2227 if errors:
2228 results.append(output_api.PresubmitError(
2229 'The name of PNG files should not have abbreviations. \n'
2230 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2231 'Contact [email protected] if you have questions.', errors))
2232 return results
2233
2234
Daniel Cheng4dcdb6b2017-04-13 08:30:172235def _ExtractAddRulesFromParsedDeps(parsed_deps):
2236 """Extract the rules that add dependencies from a parsed DEPS file.
2237
2238 Args:
2239 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2240 add_rules = set()
2241 add_rules.update([
2242 rule[1:] for rule in parsed_deps.get('include_rules', [])
2243 if rule.startswith('+') or rule.startswith('!')
2244 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502245 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172246 {}).iteritems():
2247 add_rules.update([
2248 rule[1:] for rule in rules
2249 if rule.startswith('+') or rule.startswith('!')
2250 ])
2251 return add_rules
2252
2253
2254def _ParseDeps(contents):
2255 """Simple helper for parsing DEPS files."""
2256 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172257 class _VarImpl:
2258
2259 def __init__(self, local_scope):
2260 self._local_scope = local_scope
2261
2262 def Lookup(self, var_name):
2263 """Implements the Var syntax."""
2264 try:
2265 return self._local_scope['vars'][var_name]
2266 except KeyError:
2267 raise Exception('Var is not defined: %s' % var_name)
2268
2269 local_scope = {}
2270 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172271 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592272 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172273 }
2274 exec contents in global_scope, local_scope
2275 return local_scope
2276
2277
2278def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592279 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412280 a set of DEPS entries that we should look up.
2281
2282 For a directory (rather than a specific filename) we fake a path to
2283 a specific filename by adding /DEPS. This is chosen as a file that
2284 will seldom or never be subject to per-file include_rules.
2285 """
[email protected]2b438d62013-11-14 17:54:142286 # We ignore deps entries on auto-generated directories.
2287 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082288
Daniel Cheng4dcdb6b2017-04-13 08:30:172289 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2290 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2291
2292 added_deps = new_deps.difference(old_deps)
2293
[email protected]2b438d62013-11-14 17:54:142294 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172295 for added_dep in added_deps:
2296 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2297 continue
2298 # Assume that a rule that ends in .h is a rule for a specific file.
2299 if added_dep.endswith('.h'):
2300 results.add(added_dep)
2301 else:
2302 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082303 return results
2304
2305
Saagar Sanghavifceeaae2020-08-12 16:40:362306def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552307 """When a dependency prefixed with + is added to a DEPS file, we
2308 want to make sure that the change is reviewed by an OWNER of the
2309 target file or directory, to avoid layering violations from being
2310 introduced. This check verifies that this happens.
2311 """
Joey Mou57048132021-02-26 22:17:552312 # We rely on Gerrit's code-owners to check approvals.
2313 # input_api.gerrit is always set for Chromium, but other projects
2314 # might not use Gerrit.
2315 if not input_api.gerrit:
2316 return []
Edward Lesmes6fba51082021-01-20 04:20:232317 if input_api.change.issue:
2318 # Skip OWNERS check when Bot-Commit label is approved. This label is
2319 # intended for commits made by trusted bots that don't require review nor
2320 # owners approval.
2321 if input_api.gerrit.IsBotCommitApproved(input_api.change.issue):
2322 return []
2323 # Skip OWNERS check when Owners-Override label is approved. This is intended
2324 # for global owners, trusted bots, and on-call sheriffs. Review is still
2325 # required for these changes.
2326 if input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue):
2327 return []
2328
Daniel Cheng4dcdb6b2017-04-13 08:30:172329 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242330
2331 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492332 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242333 for f in input_api.AffectedFiles(include_deletes=False,
2334 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552335 filename = input_api.os_path.basename(f.LocalPath())
2336 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172337 virtual_depended_on_files.update(_CalculateAddedDeps(
2338 input_api.os_path,
2339 '\n'.join(f.OldContents()),
2340 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552341
[email protected]e871964c2013-05-13 14:14:552342 if not virtual_depended_on_files:
2343 return []
2344
2345 if input_api.is_committing:
2346 if input_api.tbr:
2347 return [output_api.PresubmitNotifyResult(
2348 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272349 if input_api.dry_run:
2350 return [output_api.PresubmitNotifyResult(
2351 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552352 if not input_api.change.issue:
2353 return [output_api.PresubmitError(
2354 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402355 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552356 output = output_api.PresubmitError
2357 else:
2358 output = output_api.PresubmitNotifyResult
2359
tandriied3b7e12016-05-12 14:38:502360 owner_email, reviewers = (
2361 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2362 input_api,
Edward Lesmesa3846442021-02-08 20:20:032363 None,
tandriied3b7e12016-05-12 14:38:502364 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552365
2366 owner_email = owner_email or input_api.change.author_email
2367
Edward Lesmesa3846442021-02-08 20:20:032368 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2369 virtual_depended_on_files, reviewers.union([owner_email]), [])
2370 missing_files = [
2371 f for f in virtual_depended_on_files
2372 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412373
2374 # We strip the /DEPS part that was added by
2375 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2376 # directory.
2377 def StripDeps(path):
2378 start_deps = path.rfind('/DEPS')
2379 if start_deps != -1:
2380 return path[:start_deps]
2381 else:
2382 return path
2383 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552384 for path in missing_files]
2385
2386 if unapproved_dependencies:
2387 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152388 output('You need LGTM from owners of depends-on paths in DEPS that were '
2389 'modified in this CL:\n %s' %
2390 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032391 suggested_owners = input_api.owners_client.SuggestOwners(
2392 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152393 output_list.append(output(
2394 'Suggested missing target path OWNERS:\n %s' %
2395 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552396 return output_list
2397
2398 return []
2399
2400
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492401# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362402def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492403 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442404 files_to_skip = (_EXCLUDED_PATHS +
2405 _TEST_CODE_EXCLUDED_PATHS +
2406 input_api.DEFAULT_FILES_TO_SKIP +
2407 (r"^base[\\/]logging\.h$",
2408 r"^base[\\/]logging\.cc$",
2409 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2410 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2411 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2412 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2413 r"startup_browser_creator\.cc$",
2414 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2415 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2416 r"diagnostics_writer\.cc$",
2417 r"^chrome[\\/]chrome_cleaner[\\/].*",
2418 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2419 r"dll_hash_main\.cc$",
2420 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2421 r"^chromecast[\\/]",
2422 r"^cloud_print[\\/]",
2423 r"^components[\\/]browser_watcher[\\/]"
2424 r"dump_stability_report_main_win.cc$",
2425 r"^components[\\/]media_control[\\/]renderer[\\/]"
2426 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352427 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2428 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442429 r"^components[\\/]zucchini[\\/].*",
2430 # TODO(peter): Remove exception. https://crbug.com/534537
2431 r"^content[\\/]browser[\\/]notifications[\\/]"
2432 r"notification_event_dispatcher_impl\.cc$",
2433 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2434 r"gl_helper_benchmark\.cc$",
2435 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2436 r"^courgette[\\/]courgette_tool\.cc$",
2437 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2438 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2439 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2440 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2441 r"^ipc[\\/]ipc_logging\.cc$",
2442 r"^native_client_sdk[\\/]",
2443 r"^remoting[\\/]base[\\/]logging\.h$",
2444 r"^remoting[\\/]host[\\/].*",
2445 r"^sandbox[\\/]linux[\\/].*",
2446 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2447 r"dump_file_system.cc$",
2448 r"^tools[\\/]",
2449 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2450 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2451 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2452 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2453 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402454 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442455 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402456
thomasanderson625d3932017-03-29 07:16:582457 log_info = set([])
2458 printf = set([])
[email protected]85218562013-11-22 07:41:402459
2460 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582461 for _, line in f.ChangedContents():
2462 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2463 log_info.add(f.LocalPath())
2464 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2465 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372466
thomasanderson625d3932017-03-29 07:16:582467 if input_api.re.search(r"\bprintf\(", line):
2468 printf.add(f.LocalPath())
2469 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2470 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402471
2472 if log_info:
2473 return [output_api.PresubmitError(
2474 'These files spam the console log with LOG(INFO):',
2475 items=log_info)]
2476 if printf:
2477 return [output_api.PresubmitError(
2478 'These files spam the console log with printf/fprintf:',
2479 items=printf)]
2480 return []
2481
2482
Saagar Sanghavifceeaae2020-08-12 16:40:362483def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162484 """These types are all expected to hold locks while in scope and
2485 so should never be anonymous (which causes them to be immediately
2486 destroyed)."""
2487 they_who_must_be_named = [
2488 'base::AutoLock',
2489 'base::AutoReset',
2490 'base::AutoUnlock',
2491 'SkAutoAlphaRestore',
2492 'SkAutoBitmapShaderInstall',
2493 'SkAutoBlitterChoose',
2494 'SkAutoBounderCommit',
2495 'SkAutoCallProc',
2496 'SkAutoCanvasRestore',
2497 'SkAutoCommentBlock',
2498 'SkAutoDescriptor',
2499 'SkAutoDisableDirectionCheck',
2500 'SkAutoDisableOvalCheck',
2501 'SkAutoFree',
2502 'SkAutoGlyphCache',
2503 'SkAutoHDC',
2504 'SkAutoLockColors',
2505 'SkAutoLockPixels',
2506 'SkAutoMalloc',
2507 'SkAutoMaskFreeImage',
2508 'SkAutoMutexAcquire',
2509 'SkAutoPathBoundsUpdate',
2510 'SkAutoPDFRelease',
2511 'SkAutoRasterClipValidate',
2512 'SkAutoRef',
2513 'SkAutoTime',
2514 'SkAutoTrace',
2515 'SkAutoUnref',
2516 ]
2517 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2518 # bad: base::AutoLock(lock.get());
2519 # not bad: base::AutoLock lock(lock.get());
2520 bad_pattern = input_api.re.compile(anonymous)
2521 # good: new base::AutoLock(lock.get())
2522 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2523 errors = []
2524
2525 for f in input_api.AffectedFiles():
2526 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2527 continue
2528 for linenum, line in f.ChangedContents():
2529 if bad_pattern.search(line) and not good_pattern.search(line):
2530 errors.append('%s:%d' % (f.LocalPath(), linenum))
2531
2532 if errors:
2533 return [output_api.PresubmitError(
2534 'These lines create anonymous variables that need to be named:',
2535 items=errors)]
2536 return []
2537
2538
Saagar Sanghavifceeaae2020-08-12 16:40:362539def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532540 # Returns whether |template_str| is of the form <T, U...> for some types T
2541 # and U. Assumes that |template_str| is already in the form <...>.
2542 def HasMoreThanOneArg(template_str):
2543 # Level of <...> nesting.
2544 nesting = 0
2545 for c in template_str:
2546 if c == '<':
2547 nesting += 1
2548 elif c == '>':
2549 nesting -= 1
2550 elif c == ',' and nesting == 1:
2551 return True
2552 return False
2553
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492554 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102555 sources = lambda affected_file: input_api.FilterSourceFile(
2556 affected_file,
James Cook24a504192020-07-23 00:08:442557 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2558 input_api.DEFAULT_FILES_TO_SKIP),
2559 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552560
2561 # Pattern to capture a single "<...>" block of template arguments. It can
2562 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2563 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2564 # latter would likely require counting that < and > match, which is not
2565 # expressible in regular languages. Should the need arise, one can introduce
2566 # limited counting (matching up to a total number of nesting depth), which
2567 # should cover all practical cases for already a low nesting limit.
2568 template_arg_pattern = (
2569 r'<[^>]*' # Opening block of <.
2570 r'>([^<]*>)?') # Closing block of >.
2571 # Prefix expressing that whatever follows is not already inside a <...>
2572 # block.
2573 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102574 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552575 not_inside_template_arg_pattern
2576 + r'\bstd::unique_ptr'
2577 + template_arg_pattern
2578 + r'\(\)')
2579
2580 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2581 template_arg_no_array_pattern = (
2582 r'<[^>]*[^]]' # Opening block of <.
2583 r'>([^(<]*[^]]>)?') # Closing block of >.
2584 # Prefix saying that what follows is the start of an expression.
2585 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2586 # Suffix saying that what follows are call parentheses with a non-empty list
2587 # of arguments.
2588 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532589 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552590 return_construct_pattern = input_api.re.compile(
2591 start_of_expr_pattern
2592 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532593 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552594 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532595 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552596 + nonempty_arg_list_pattern)
2597
Vaclav Brozek851d9602018-04-04 16:13:052598 problems_constructor = []
2599 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102600 for f in input_api.AffectedSourceFiles(sources):
2601 for line_number, line in f.ChangedContents():
2602 # Disallow:
2603 # return std::unique_ptr<T>(foo);
2604 # bar = std::unique_ptr<T>(foo);
2605 # But allow:
2606 # return std::unique_ptr<T[]>(foo);
2607 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532608 # And also allow cases when the second template argument is present. Those
2609 # cases cannot be handled by std::make_unique:
2610 # return std::unique_ptr<T, U>(foo);
2611 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052612 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532613 return_construct_result = return_construct_pattern.search(line)
2614 if return_construct_result and not HasMoreThanOneArg(
2615 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052616 problems_constructor.append(
2617 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102618 # Disallow:
2619 # std::unique_ptr<T>()
2620 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052621 problems_nullptr.append(
2622 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2623
2624 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162625 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052626 errors.append(output_api.PresubmitError(
2627 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162628 problems_nullptr))
2629 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052630 errors.append(output_api.PresubmitError(
2631 'The following files use explicit std::unique_ptr constructor.'
2632 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162633 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102634 return errors
2635
2636
Saagar Sanghavifceeaae2020-08-12 16:40:362637def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082638 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522639 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082640 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522641 # If actions.xml is already included in the changelist, the PRESUBMIT
2642 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082643 return []
2644
[email protected]999261d2014-03-03 20:08:082645 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2646 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522647 current_actions = None
[email protected]999261d2014-03-03 20:08:082648 for f in input_api.AffectedFiles(file_filter=file_filter):
2649 for line_num, line in f.ChangedContents():
2650 match = input_api.re.search(action_re, line)
2651 if match:
[email protected]2f92dec2014-03-07 19:21:522652 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2653 # loaded only once.
2654 if not current_actions:
2655 with open('tools/metrics/actions/actions.xml') as actions_f:
2656 current_actions = actions_f.read()
2657 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082658 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522659 action = 'name="{0}"'.format(action_name)
2660 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082661 return [output_api.PresubmitPromptWarning(
2662 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522663 'tools/metrics/actions/actions.xml. Please run '
2664 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082665 % (f.LocalPath(), line_num, action_name))]
2666 return []
2667
2668
Daniel Cheng13ca61a882017-08-25 15:11:252669def _ImportJSONCommentEater(input_api):
2670 import sys
2671 sys.path = sys.path + [input_api.os_path.join(
2672 input_api.PresubmitLocalPath(),
2673 'tools', 'json_comment_eater')]
2674 import json_comment_eater
2675 return json_comment_eater
2676
2677
[email protected]99171a92014-06-03 08:44:472678def _GetJSONParseError(input_api, filename, eat_comments=True):
2679 try:
2680 contents = input_api.ReadFile(filename)
2681 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252682 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132683 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472684
2685 input_api.json.loads(contents)
2686 except ValueError as e:
2687 return e
2688 return None
2689
2690
2691def _GetIDLParseError(input_api, filename):
2692 try:
2693 contents = input_api.ReadFile(filename)
2694 idl_schema = input_api.os_path.join(
2695 input_api.PresubmitLocalPath(),
2696 'tools', 'json_schema_compiler', 'idl_schema.py')
2697 process = input_api.subprocess.Popen(
2698 [input_api.python_executable, idl_schema],
2699 stdin=input_api.subprocess.PIPE,
2700 stdout=input_api.subprocess.PIPE,
2701 stderr=input_api.subprocess.PIPE,
2702 universal_newlines=True)
2703 (_, error) = process.communicate(input=contents)
2704 return error or None
2705 except ValueError as e:
2706 return e
2707
2708
Saagar Sanghavifceeaae2020-08-12 16:40:362709def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472710 """Check that IDL and JSON files do not contain syntax errors."""
2711 actions = {
2712 '.idl': _GetIDLParseError,
2713 '.json': _GetJSONParseError,
2714 }
[email protected]99171a92014-06-03 08:44:472715 # Most JSON files are preprocessed and support comments, but these do not.
2716 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042717 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472718 ]
2719 # Only run IDL checker on files in these directories.
2720 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042721 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2722 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472723 ]
2724
2725 def get_action(affected_file):
2726 filename = affected_file.LocalPath()
2727 return actions.get(input_api.os_path.splitext(filename)[1])
2728
[email protected]99171a92014-06-03 08:44:472729 def FilterFile(affected_file):
2730 action = get_action(affected_file)
2731 if not action:
2732 return False
2733 path = affected_file.LocalPath()
2734
Erik Staab2dd72b12020-04-16 15:03:402735 if _MatchesFile(input_api,
2736 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2737 path):
[email protected]99171a92014-06-03 08:44:472738 return False
2739
2740 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162741 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472742 return False
2743 return True
2744
2745 results = []
2746 for affected_file in input_api.AffectedFiles(
2747 file_filter=FilterFile, include_deletes=False):
2748 action = get_action(affected_file)
2749 kwargs = {}
2750 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162751 _MatchesFile(input_api, json_no_comments_patterns,
2752 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472753 kwargs['eat_comments'] = False
2754 parse_error = action(input_api,
2755 affected_file.AbsoluteLocalPath(),
2756 **kwargs)
2757 if parse_error:
2758 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2759 (affected_file.LocalPath(), parse_error)))
2760 return results
2761
2762
Saagar Sanghavifceeaae2020-08-12 16:40:362763def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492764 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472765 import sys
[email protected]760deea2013-12-10 19:33:492766 original_sys_path = sys.path
2767 try:
2768 sys.path = sys.path + [input_api.os_path.join(
2769 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2770 import checkstyle
2771 finally:
2772 # Restore sys.path to what it was before.
2773 sys.path = original_sys_path
2774
2775 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092776 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442777 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492778
2779
Saagar Sanghavifceeaae2020-08-12 16:40:362780def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002781 """Checks to make sure devil is initialized correctly in python scripts."""
2782 script_common_initialize_pattern = input_api.re.compile(
2783 r'script_common\.InitializeEnvironment\(')
2784 devil_env_config_initialize = input_api.re.compile(
2785 r'devil_env\.config\.Initialize\(')
2786
2787 errors = []
2788
2789 sources = lambda affected_file: input_api.FilterSourceFile(
2790 affected_file,
James Cook24a504192020-07-23 00:08:442791 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2792 (r'^build[\\/]android[\\/]devil_chromium\.py',
2793 r'^third_party[\\/].*',)),
2794 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002795
2796 for f in input_api.AffectedSourceFiles(sources):
2797 for line_num, line in f.ChangedContents():
2798 if (script_common_initialize_pattern.search(line) or
2799 devil_env_config_initialize.search(line)):
2800 errors.append("%s:%d" % (f.LocalPath(), line_num))
2801
2802 results = []
2803
2804 if errors:
2805 results.append(output_api.PresubmitError(
2806 'Devil initialization should always be done using '
2807 'devil_chromium.Initialize() in the chromium project, to use better '
2808 'defaults for dependencies (ex. up-to-date version of adb).',
2809 errors))
2810
2811 return results
2812
2813
Sean Kau46e29bc2017-08-28 16:31:162814def _MatchesFile(input_api, patterns, path):
2815 for pattern in patterns:
2816 if input_api.re.search(pattern, path):
2817 return True
2818 return False
2819
2820
Daniel Cheng7052cdf2017-11-21 19:23:292821def _GetOwnersFilesToCheckForIpcOwners(input_api):
2822 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172823
Daniel Cheng7052cdf2017-11-21 19:23:292824 Returns:
2825 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2826 contain to cover IPC-related files with noparent reviewer rules.
2827 """
2828 # Whether or not a file affects IPC is (mostly) determined by a simple list
2829 # of filename patterns.
dchenge07de812016-06-20 19:27:172830 file_patterns = [
palmerb19a0932017-01-24 04:00:312831 # Legacy IPC:
dchenge07de812016-06-20 19:27:172832 '*_messages.cc',
2833 '*_messages*.h',
2834 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312835 # Mojo IPC:
dchenge07de812016-06-20 19:27:172836 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472837 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172838 '*_struct_traits*.*',
2839 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312840 '*.typemap',
2841 # Android native IPC:
2842 '*.aidl',
2843 # Blink uses a different file naming convention:
2844 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472845 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172846 '*StructTraits*.*',
2847 '*TypeConverter*.*',
2848 ]
2849
scottmg7a6ed5ba2016-11-04 18:22:042850 # These third_party directories do not contain IPCs, but contain files
2851 # matching the above patterns, which trigger false positives.
2852 exclude_paths = [
2853 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162854 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232855 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292856 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542857 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162858 # These files are just used to communicate between class loaders running
2859 # in the same process.
2860 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572861 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2862
scottmg7a6ed5ba2016-11-04 18:22:042863 ]
2864
dchenge07de812016-06-20 19:27:172865 # Dictionary mapping an OWNERS file path to Patterns.
2866 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2867 # rules ) to a PatternEntry.
2868 # PatternEntry is a dictionary with two keys:
2869 # - 'files': the files that are matched by this pattern
2870 # - 'rules': the per-file rules needed for this pattern
2871 # For example, if we expect OWNERS file to contain rules for *.mojom and
2872 # *_struct_traits*.*, Patterns might look like this:
2873 # {
2874 # '*.mojom': {
2875 # 'files': ...,
2876 # 'rules': [
2877 # 'per-file *.mojom=set noparent',
2878 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2879 # ],
2880 # },
2881 # '*_struct_traits*.*': {
2882 # 'files': ...,
2883 # 'rules': [
2884 # 'per-file *_struct_traits*.*=set noparent',
2885 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2886 # ],
2887 # },
2888 # }
2889 to_check = {}
2890
Daniel Cheng13ca61a882017-08-25 15:11:252891 def AddPatternToCheck(input_file, pattern):
2892 owners_file = input_api.os_path.join(
2893 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2894 if owners_file not in to_check:
2895 to_check[owners_file] = {}
2896 if pattern not in to_check[owners_file]:
2897 to_check[owners_file][pattern] = {
2898 'files': [],
2899 'rules': [
2900 'per-file %s=set noparent' % pattern,
2901 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2902 ]
2903 }
Vaclav Brozekd5de76a2018-03-17 07:57:502904 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252905
dchenge07de812016-06-20 19:27:172906 # Iterate through the affected files to see what we actually need to check
2907 # for. We should only nag patch authors about per-file rules if a file in that
2908 # directory would match that pattern. If a directory only contains *.mojom
2909 # files and no *_messages*.h files, we should only nag about rules for
2910 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252911 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262912 # Manifest files don't have a strong naming convention. Instead, try to find
2913 # affected .cc and .h files which look like they contain a manifest
2914 # definition.
2915 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2916 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2917 if (manifest_pattern.search(f.LocalPath()) and not
2918 test_manifest_pattern.search(f.LocalPath())):
2919 # We expect all actual service manifest files to contain at least one
2920 # qualified reference to service_manager::Manifest.
2921 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252922 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172923 for pattern in file_patterns:
2924 if input_api.fnmatch.fnmatch(
2925 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042926 skip = False
2927 for exclude in exclude_paths:
2928 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2929 skip = True
2930 break
2931 if skip:
2932 continue
Daniel Cheng13ca61a882017-08-25 15:11:252933 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172934 break
2935
Daniel Cheng7052cdf2017-11-21 19:23:292936 return to_check
2937
2938
Wez17c66962020-04-29 15:26:032939def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2940 """Adds OWNERS files to check for correct Fuchsia security owners."""
2941
2942 file_patterns = [
2943 # Component specifications.
2944 '*.cml', # Component Framework v2.
2945 '*.cmx', # Component Framework v1.
2946
2947 # Fuchsia IDL protocol specifications.
2948 '*.fidl',
2949 ]
2950
Joshua Peraza1ca6d392020-12-08 00:14:092951 # Don't check for owners files for changes in these directories.
2952 exclude_paths = [
2953 'third_party/crashpad/*',
2954 ]
2955
Wez17c66962020-04-29 15:26:032956 def AddPatternToCheck(input_file, pattern):
2957 owners_file = input_api.os_path.join(
2958 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2959 if owners_file not in to_check:
2960 to_check[owners_file] = {}
2961 if pattern not in to_check[owners_file]:
2962 to_check[owners_file][pattern] = {
2963 'files': [],
2964 'rules': [
2965 'per-file %s=set noparent' % pattern,
2966 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2967 ]
2968 }
2969 to_check[owners_file][pattern]['files'].append(input_file)
2970
2971 # Iterate through the affected files to see what we actually need to check
2972 # for. We should only nag patch authors about per-file rules if a file in that
2973 # directory would match that pattern.
2974 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092975 skip = False
2976 for exclude in exclude_paths:
2977 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2978 skip = True
2979 if skip:
2980 continue
2981
Wez17c66962020-04-29 15:26:032982 for pattern in file_patterns:
2983 if input_api.fnmatch.fnmatch(
2984 input_api.os_path.basename(f.LocalPath()), pattern):
2985 AddPatternToCheck(f, pattern)
2986 break
2987
2988 return to_check
2989
2990
Saagar Sanghavifceeaae2020-08-12 16:40:362991def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292992 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2993 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032994 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292995
2996 if to_check:
2997 # If there are any OWNERS files to check, there are IPC-related changes in
2998 # this CL. Auto-CC the review list.
2999 output_api.AppendCC('[email protected]')
3000
3001 # Go through the OWNERS files to check, filtering out rules that are already
3002 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173003 for owners_file, patterns in to_check.iteritems():
3004 try:
3005 with file(owners_file) as f:
3006 lines = set(f.read().splitlines())
3007 for entry in patterns.itervalues():
3008 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3009 ]
3010 except IOError:
3011 # No OWNERS file, so all the rules are definitely missing.
3012 continue
3013
3014 # All the remaining lines weren't found in OWNERS files, so emit an error.
3015 errors = []
3016 for owners_file, patterns in to_check.iteritems():
3017 missing_lines = []
3018 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503019 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173020 missing_lines.extend(entry['rules'])
3021 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3022 if missing_lines:
3023 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053024 'Because of the presence of files:\n%s\n\n'
3025 '%s needs the following %d lines added:\n\n%s' %
3026 ('\n'.join(files), owners_file, len(missing_lines),
3027 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173028
3029 results = []
3030 if errors:
vabrf5ce3bf92016-07-11 14:52:413031 if input_api.is_committing:
3032 output = output_api.PresubmitError
3033 else:
3034 output = output_api.PresubmitPromptWarning
3035 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593036 'Found OWNERS files that need to be updated for IPC security ' +
3037 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173038 long_text='\n\n'.join(errors)))
3039
3040 return results
3041
3042
Robert Sesek2c905332020-05-06 23:17:133043def _GetFilesUsingSecurityCriticalFunctions(input_api):
3044 """Checks affected files for changes to security-critical calls. This
3045 function checks the full change diff, to catch both additions/changes
3046 and removals.
3047
3048 Returns a dict keyed by file name, and the value is a set of detected
3049 functions.
3050 """
3051 # Map of function pretty name (displayed in an error) to the pattern to
3052 # match it with.
3053 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373054 'content::GetServiceSandboxType<>()':
3055 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133056 }
3057 _PATTERNS_TO_CHECK = {
3058 k: input_api.re.compile(v)
3059 for k, v in _PATTERNS_TO_CHECK.items()
3060 }
3061
3062 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3063 files_to_functions = {}
3064 for f in input_api.AffectedFiles():
3065 diff = f.GenerateScmDiff()
3066 for line in diff.split('\n'):
3067 # Not using just RightHandSideLines() because removing a
3068 # call to a security-critical function can be just as important
3069 # as adding or changing the arguments.
3070 if line.startswith('-') or (line.startswith('+') and
3071 not line.startswith('++')):
3072 for name, pattern in _PATTERNS_TO_CHECK.items():
3073 if pattern.search(line):
3074 path = f.LocalPath()
3075 if not path in files_to_functions:
3076 files_to_functions[path] = set()
3077 files_to_functions[path].add(name)
3078 return files_to_functions
3079
3080
Saagar Sanghavifceeaae2020-08-12 16:40:363081def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133082 """Checks that changes involving security-critical functions are reviewed
3083 by the security team.
3084 """
3085 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123086 if not len(files_to_functions):
3087 return []
Robert Sesek2c905332020-05-06 23:17:133088
Edward Lesmes1e9fade2021-02-08 20:31:123089 owner_email, reviewers = (
3090 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3091 input_api,
3092 None,
3093 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133094
Edward Lesmes1e9fade2021-02-08 20:31:123095 # Load the OWNERS file for security changes.
3096 owners_file = 'ipc/SECURITY_OWNERS'
3097 security_owners = input_api.owners_client.ListOwners(owners_file)
3098 has_security_owner = any([owner in reviewers for owner in security_owners])
3099 if has_security_owner:
3100 return []
Robert Sesek2c905332020-05-06 23:17:133101
Edward Lesmes1e9fade2021-02-08 20:31:123102 msg = 'The following files change calls to security-sensive functions\n' \
3103 'that need to be reviewed by {}.\n'.format(owners_file)
3104 for path, names in files_to_functions.items():
3105 msg += ' {}\n'.format(path)
3106 for name in names:
3107 msg += ' {}\n'.format(name)
3108 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133109
Edward Lesmes1e9fade2021-02-08 20:31:123110 if input_api.is_committing:
3111 output = output_api.PresubmitError
3112 else:
3113 output = output_api.PresubmitNotifyResult
3114 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133115
3116
Saagar Sanghavifceeaae2020-08-12 16:40:363117def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263118 """Checks that set noparent is only used together with an OWNERS file in
3119 //build/OWNERS.setnoparent (see also
3120 //docs/code_reviews.md#owners-files-details)
3121 """
3122 errors = []
3123
3124 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3125 allowed_owners_files = set()
3126 with open(allowed_owners_files_file, 'r') as f:
3127 for line in f:
3128 line = line.strip()
3129 if not line or line.startswith('#'):
3130 continue
3131 allowed_owners_files.add(line)
3132
3133 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3134
3135 for f in input_api.AffectedFiles(include_deletes=False):
3136 if not f.LocalPath().endswith('OWNERS'):
3137 continue
3138
3139 found_owners_files = set()
3140 found_set_noparent_lines = dict()
3141
3142 # Parse the OWNERS file.
3143 for lineno, line in enumerate(f.NewContents(), 1):
3144 line = line.strip()
3145 if line.startswith('set noparent'):
3146 found_set_noparent_lines[''] = lineno
3147 if line.startswith('file://'):
3148 if line in allowed_owners_files:
3149 found_owners_files.add('')
3150 if line.startswith('per-file'):
3151 match = per_file_pattern.match(line)
3152 if match:
3153 glob = match.group(1).strip()
3154 directive = match.group(2).strip()
3155 if directive == 'set noparent':
3156 found_set_noparent_lines[glob] = lineno
3157 if directive.startswith('file://'):
3158 if directive in allowed_owners_files:
3159 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153160
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263161 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403162 # listed in build/OWNERS.setnoparent. An exception is made for top level
3163 # directories since src/OWNERS shouldn't review them.
3164 if f.LocalPath().count('/') != 1:
3165 for set_noparent_line in found_set_noparent_lines:
3166 if set_noparent_line in found_owners_files:
3167 continue
3168 errors.append(' %s:%d' % (f.LocalPath(),
3169 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263170
3171 results = []
3172 if errors:
3173 if input_api.is_committing:
3174 output = output_api.PresubmitError
3175 else:
3176 output = output_api.PresubmitPromptWarning
3177 results.append(output(
3178 'Found the following "set noparent" restrictions in OWNERS files that '
3179 'do not include owners from build/OWNERS.setnoparent:',
3180 long_text='\n\n'.join(errors)))
3181 return results
3182
3183
Saagar Sanghavifceeaae2020-08-12 16:40:363184def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313185 """Checks that added or removed lines in non third party affected
3186 header files do not lead to new useless class or struct forward
3187 declaration.
jbriance9e12f162016-11-25 07:57:503188 """
3189 results = []
3190 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3191 input_api.re.MULTILINE)
3192 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3193 input_api.re.MULTILINE)
3194 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313195 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193196 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493197 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313198 continue
3199
jbriance9e12f162016-11-25 07:57:503200 if not f.LocalPath().endswith('.h'):
3201 continue
3202
3203 contents = input_api.ReadFile(f)
3204 fwd_decls = input_api.re.findall(class_pattern, contents)
3205 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3206
3207 useless_fwd_decls = []
3208 for decl in fwd_decls:
3209 count = sum(1 for _ in input_api.re.finditer(
3210 r'\b%s\b' % input_api.re.escape(decl), contents))
3211 if count == 1:
3212 useless_fwd_decls.append(decl)
3213
3214 if not useless_fwd_decls:
3215 continue
3216
3217 for line in f.GenerateScmDiff().splitlines():
3218 if (line.startswith('-') and not line.startswith('--') or
3219 line.startswith('+') and not line.startswith('++')):
3220 for decl in useless_fwd_decls:
3221 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3222 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243223 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503224 (f.LocalPath(), decl)))
3225 useless_fwd_decls.remove(decl)
3226
3227 return results
3228
Jinsong Fan91ebbbd2019-04-16 14:57:173229def _CheckAndroidDebuggableBuild(input_api, output_api):
3230 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3231 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3232 this is a debuggable build of Android.
3233 """
3234 build_type_check_pattern = input_api.re.compile(
3235 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3236
3237 errors = []
3238
3239 sources = lambda affected_file: input_api.FilterSourceFile(
3240 affected_file,
James Cook24a504192020-07-23 00:08:443241 files_to_skip=(_EXCLUDED_PATHS +
3242 _TEST_CODE_EXCLUDED_PATHS +
3243 input_api.DEFAULT_FILES_TO_SKIP +
3244 (r"^android_webview[\\/]support_library[\\/]"
3245 "boundary_interfaces[\\/]",
3246 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3247 r'^third_party[\\/].*',
3248 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3249 r"webview[\\/]chromium[\\/]License.*",)),
3250 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173251
3252 for f in input_api.AffectedSourceFiles(sources):
3253 for line_num, line in f.ChangedContents():
3254 if build_type_check_pattern.search(line):
3255 errors.append("%s:%d" % (f.LocalPath(), line_num))
3256
3257 results = []
3258
3259 if errors:
3260 results.append(output_api.PresubmitPromptWarning(
3261 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3262 ' Please use BuildInfo.isDebugAndroid() instead.',
3263 errors))
3264
3265 return results
jbriance9e12f162016-11-25 07:57:503266
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493267# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293268def _CheckAndroidToastUsage(input_api, output_api):
3269 """Checks that code uses org.chromium.ui.widget.Toast instead of
3270 android.widget.Toast (Chromium Toast doesn't force hardware
3271 acceleration on low-end devices, saving memory).
3272 """
3273 toast_import_pattern = input_api.re.compile(
3274 r'^import android\.widget\.Toast;$')
3275
3276 errors = []
3277
3278 sources = lambda affected_file: input_api.FilterSourceFile(
3279 affected_file,
James Cook24a504192020-07-23 00:08:443280 files_to_skip=(_EXCLUDED_PATHS +
3281 _TEST_CODE_EXCLUDED_PATHS +
3282 input_api.DEFAULT_FILES_TO_SKIP +
3283 (r'^chromecast[\\/].*',
3284 r'^remoting[\\/].*')),
3285 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293286
3287 for f in input_api.AffectedSourceFiles(sources):
3288 for line_num, line in f.ChangedContents():
3289 if toast_import_pattern.search(line):
3290 errors.append("%s:%d" % (f.LocalPath(), line_num))
3291
3292 results = []
3293
3294 if errors:
3295 results.append(output_api.PresubmitError(
3296 'android.widget.Toast usage is detected. Android toasts use hardware'
3297 ' acceleration, and can be\ncostly on low-end devices. Please use'
3298 ' org.chromium.ui.widget.Toast instead.\n'
3299 'Contact [email protected] if you have any questions.',
3300 errors))
3301
3302 return results
3303
3304
dgnaa68d5e2015-06-10 10:08:223305def _CheckAndroidCrLogUsage(input_api, output_api):
3306 """Checks that new logs using org.chromium.base.Log:
3307 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513308 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223309 """
pkotwicza1dd0b002016-05-16 14:41:043310
torne89540622017-03-24 19:41:303311 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043312 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303313 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043314 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303315 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043316 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3317 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093318 # The customtabs_benchmark is a small app that does not depend on Chromium
3319 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043320 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043321 ]
3322
dgnaa68d5e2015-06-10 10:08:223323 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123324 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3325 class_in_base_pattern = input_api.re.compile(
3326 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3327 has_some_log_import_pattern = input_api.re.compile(
3328 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223329 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553330 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223331 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463332 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553333 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223334
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463335 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443336 sources = lambda x: input_api.FilterSourceFile(x,
3337 files_to_check=[r'.*\.java$'],
3338 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123339
dgnaa68d5e2015-06-10 10:08:223340 tag_decl_errors = []
3341 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123342 tag_errors = []
dgn38736db2015-09-18 19:20:513343 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123344 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223345
3346 for f in input_api.AffectedSourceFiles(sources):
3347 file_content = input_api.ReadFile(f)
3348 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223349 # Per line checks
dgn87d9fb62015-06-12 09:15:123350 if (cr_log_import_pattern.search(file_content) or
3351 (class_in_base_pattern.search(file_content) and
3352 not has_some_log_import_pattern.search(file_content))):
3353 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223354 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553355 if rough_log_decl_pattern.search(line):
3356 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223357
3358 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123359 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223360 if match:
3361 has_modified_logs = True
3362
3363 # Make sure it uses "TAG"
3364 if not match.group('tag') == 'TAG':
3365 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123366 else:
3367 # Report non cr Log function calls in changed lines
3368 for line_num, line in f.ChangedContents():
3369 if log_call_pattern.search(line):
3370 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223371
3372 # Per file checks
3373 if has_modified_logs:
3374 # Make sure the tag is using the "cr" prefix and is not too long
3375 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513376 tag_name = match.group('name') if match else None
3377 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223378 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513379 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223380 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513381 elif '.' in tag_name:
3382 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223383
3384 results = []
3385 if tag_decl_errors:
3386 results.append(output_api.PresubmitPromptWarning(
3387 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513388 '"private static final String TAG = "<package tag>".\n'
3389 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223390 tag_decl_errors))
3391
3392 if tag_length_errors:
3393 results.append(output_api.PresubmitError(
3394 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513395 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223396 tag_length_errors))
3397
3398 if tag_errors:
3399 results.append(output_api.PresubmitPromptWarning(
3400 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3401 tag_errors))
3402
dgn87d9fb62015-06-12 09:15:123403 if util_log_errors:
dgn4401aa52015-04-29 16:26:173404 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123405 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3406 util_log_errors))
3407
dgn38736db2015-09-18 19:20:513408 if tag_with_dot_errors:
3409 results.append(output_api.PresubmitPromptWarning(
3410 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3411 tag_with_dot_errors))
3412
dgn4401aa52015-04-29 16:26:173413 return results
3414
3415
Yoland Yanb92fa522017-08-28 17:37:063416def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3417 """Checks that junit.framework.* is no longer used."""
3418 deprecated_junit_framework_pattern = input_api.re.compile(
3419 r'^import junit\.framework\..*;',
3420 input_api.re.MULTILINE)
3421 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443422 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063423 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133424 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063425 for line_num, line in f.ChangedContents():
3426 if deprecated_junit_framework_pattern.search(line):
3427 errors.append("%s:%d" % (f.LocalPath(), line_num))
3428
3429 results = []
3430 if errors:
3431 results.append(output_api.PresubmitError(
3432 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3433 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3434 ' if you have any question.', errors))
3435 return results
3436
3437
3438def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3439 """Checks that if new Java test classes have inheritance.
3440 Either the new test class is JUnit3 test or it is a JUnit4 test class
3441 with a base class, either case is undesirable.
3442 """
3443 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3444
3445 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443446 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063447 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133448 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063449 if not f.OldContents():
3450 class_declaration_start_flag = False
3451 for line_num, line in f.ChangedContents():
3452 if class_declaration_pattern.search(line):
3453 class_declaration_start_flag = True
3454 if class_declaration_start_flag and ' extends ' in line:
3455 errors.append('%s:%d' % (f.LocalPath(), line_num))
3456 if '{' in line:
3457 class_declaration_start_flag = False
3458
3459 results = []
3460 if errors:
3461 results.append(output_api.PresubmitPromptWarning(
3462 'The newly created files include Test classes that inherits from base'
3463 ' class. Please do not use inheritance in JUnit4 tests or add new'
3464 ' JUnit3 tests. Contact [email protected] if you have any'
3465 ' questions.', errors))
3466 return results
3467
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203468
yolandyan45001472016-12-21 21:12:423469def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3470 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3471 deprecated_annotation_import_pattern = input_api.re.compile(
3472 r'^import android\.test\.suitebuilder\.annotation\..*;',
3473 input_api.re.MULTILINE)
3474 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443475 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423476 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133477 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423478 for line_num, line in f.ChangedContents():
3479 if deprecated_annotation_import_pattern.search(line):
3480 errors.append("%s:%d" % (f.LocalPath(), line_num))
3481
3482 results = []
3483 if errors:
3484 results.append(output_api.PresubmitError(
3485 'Annotations in android.test.suitebuilder.annotation have been'
3486 ' deprecated since API level 24. Please use android.support.test.filters'
3487 ' from //third_party/android_support_test_runner:runner_java instead.'
3488 ' Contact [email protected] if you have any questions.', errors))
3489 return results
3490
3491
agrieve7b6479d82015-10-07 14:24:223492def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3493 """Checks if MDPI assets are placed in a correct directory."""
3494 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3495 ('/res/drawable/' in f.LocalPath() or
3496 '/res/drawable-ldrtl/' in f.LocalPath()))
3497 errors = []
3498 for f in input_api.AffectedFiles(include_deletes=False,
3499 file_filter=file_filter):
3500 errors.append(' %s' % f.LocalPath())
3501
3502 results = []
3503 if errors:
3504 results.append(output_api.PresubmitError(
3505 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3506 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3507 '/res/drawable-ldrtl/.\n'
3508 'Contact [email protected] if you have questions.', errors))
3509 return results
3510
3511
Nate Fischer535972b2017-09-16 01:06:183512def _CheckAndroidWebkitImports(input_api, output_api):
3513 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353514 android.webview.ValueCallback except in the WebView glue layer
3515 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183516 """
3517 valuecallback_import_pattern = input_api.re.compile(
3518 r'^import android\.webkit\.ValueCallback;$')
3519
3520 errors = []
3521
3522 sources = lambda affected_file: input_api.FilterSourceFile(
3523 affected_file,
James Cook24a504192020-07-23 00:08:443524 files_to_skip=(_EXCLUDED_PATHS +
3525 _TEST_CODE_EXCLUDED_PATHS +
3526 input_api.DEFAULT_FILES_TO_SKIP +
3527 (r'^android_webview[\\/]glue[\\/].*',
3528 r'^weblayer[\\/].*',)),
3529 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183530
3531 for f in input_api.AffectedSourceFiles(sources):
3532 for line_num, line in f.ChangedContents():
3533 if valuecallback_import_pattern.search(line):
3534 errors.append("%s:%d" % (f.LocalPath(), line_num))
3535
3536 results = []
3537
3538 if errors:
3539 results.append(output_api.PresubmitError(
3540 'android.webkit.ValueCallback usage is detected outside of the glue'
3541 ' layer. To stay compatible with the support library, android.webkit.*'
3542 ' classes should only be used inside the glue layer and'
3543 ' org.chromium.base.Callback should be used instead.',
3544 errors))
3545
3546 return results
3547
3548
Becky Zhou7c69b50992018-12-10 19:37:573549def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3550 """Checks Android XML styles """
3551 import sys
3552 original_sys_path = sys.path
3553 try:
3554 sys.path = sys.path + [input_api.os_path.join(
3555 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3556 import checkxmlstyle
3557 finally:
3558 # Restore sys.path to what it was before.
3559 sys.path = original_sys_path
3560
3561 if is_check_on_upload:
3562 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3563 else:
3564 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3565
3566
agrievef32bcc72016-04-04 14:57:403567class PydepsChecker(object):
3568 def __init__(self, input_api, pydeps_files):
3569 self._file_cache = {}
3570 self._input_api = input_api
3571 self._pydeps_files = pydeps_files
3572
3573 def _LoadFile(self, path):
3574 """Returns the list of paths within a .pydeps file relative to //."""
3575 if path not in self._file_cache:
3576 with open(path) as f:
3577 self._file_cache[path] = f.read()
3578 return self._file_cache[path]
3579
3580 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3581 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393582 pydeps_data = self._LoadFile(pydeps_path)
3583 uses_gn_paths = '--gn-paths' in pydeps_data
3584 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3585 if uses_gn_paths:
3586 # Paths look like: //foo/bar/baz
3587 return (e[2:] for e in entries)
3588 else:
3589 # Paths look like: path/relative/to/file.pydeps
3590 os_path = self._input_api.os_path
3591 pydeps_dir = os_path.dirname(pydeps_path)
3592 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403593
3594 def _CreateFilesToPydepsMap(self):
3595 """Returns a map of local_path -> list_of_pydeps."""
3596 ret = {}
3597 for pydep_local_path in self._pydeps_files:
3598 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3599 ret.setdefault(path, []).append(pydep_local_path)
3600 return ret
3601
3602 def ComputeAffectedPydeps(self):
3603 """Returns an iterable of .pydeps files that might need regenerating."""
3604 affected_pydeps = set()
3605 file_to_pydeps_map = None
3606 for f in self._input_api.AffectedFiles(include_deletes=True):
3607 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463608 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3609 # subrepositories. We can't figure out which files change, so re-check
3610 # all files.
3611 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383612 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3613 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403614 return self._pydeps_files
3615 elif local_path.endswith('.pydeps'):
3616 if local_path in self._pydeps_files:
3617 affected_pydeps.add(local_path)
3618 elif local_path.endswith('.py'):
3619 if file_to_pydeps_map is None:
3620 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3621 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3622 return affected_pydeps
3623
3624 def DetermineIfStale(self, pydeps_path):
3625 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413626 import difflib
John Budorick47ca3fe2018-02-10 00:53:103627 import os
3628
agrievef32bcc72016-04-04 14:57:403629 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033630 if old_pydeps_data:
3631 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393632 if '--output' not in cmd:
3633 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033634 old_contents = old_pydeps_data[2:]
3635 else:
3636 # A default cmd that should work in most cases (as long as pydeps filename
3637 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3638 # file is empty/new.
3639 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3640 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3641 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103642 env = dict(os.environ)
3643 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403644 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103645 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413646 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033647 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413648 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403649
3650
Tibor Goldschwendt360793f72019-06-25 18:23:493651def _ParseGclientArgs():
3652 args = {}
3653 with open('build/config/gclient_args.gni', 'r') as f:
3654 for line in f:
3655 line = line.strip()
3656 if not line or line.startswith('#'):
3657 continue
3658 attribute, value = line.split('=')
3659 args[attribute.strip()] = value.strip()
3660 return args
3661
3662
Saagar Sanghavifceeaae2020-08-12 16:40:363663def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403664 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403665 # This check is for Python dependency lists (.pydeps files), and involves
3666 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3667 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283668 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003669 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493670 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403671 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403672 results = []
3673 # First, check for new / deleted .pydeps.
3674 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033675 # Check whether we are running the presubmit check for a file in src.
3676 # f.LocalPath is relative to repo (src, or internal repo).
3677 # os_path.exists is relative to src repo.
3678 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3679 # to src and we can conclude that the pydeps is in src.
3680 if input_api.os_path.exists(f.LocalPath()):
3681 if f.LocalPath().endswith('.pydeps'):
3682 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3683 results.append(output_api.PresubmitError(
3684 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3685 'remove %s' % f.LocalPath()))
3686 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3687 results.append(output_api.PresubmitError(
3688 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3689 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403690
3691 if results:
3692 return results
3693
Mohamed Heikal7cd4d8312020-06-16 16:49:403694 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3695 affected_pydeps = set(checker.ComputeAffectedPydeps())
3696 affected_android_pydeps = affected_pydeps.intersection(
3697 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3698 if affected_android_pydeps and not is_android:
3699 results.append(output_api.PresubmitPromptOrNotify(
3700 'You have changed python files that may affect pydeps for android\n'
3701 'specific scripts. However, the relevant presumbit check cannot be\n'
3702 'run because you are not using an Android checkout. To validate that\n'
3703 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3704 'use the android-internal-presubmit optional trybot.\n'
3705 'Possibly stale pydeps files:\n{}'.format(
3706 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403707
Mohamed Heikal7cd4d8312020-06-16 16:49:403708 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3709 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403710 try:
phajdan.jr0d9878552016-11-04 10:49:413711 result = checker.DetermineIfStale(pydep_path)
3712 if result:
3713 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403714 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413715 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3716 'To regenerate, run:\n\n %s' %
3717 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403718 except input_api.subprocess.CalledProcessError as error:
3719 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3720 long_text=error.output)]
3721
3722 return results
3723
3724
Saagar Sanghavifceeaae2020-08-12 16:40:363725def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433726 """Checks to make sure no header files have |Singleton<|."""
3727 def FileFilter(affected_file):
3728 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443729 files_to_skip = (_EXCLUDED_PATHS +
3730 input_api.DEFAULT_FILES_TO_SKIP +
3731 (r"^base[\\/]memory[\\/]singleton\.h$",
3732 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3733 r"quic_singleton_impl\.h$"))
3734 return input_api.FilterSourceFile(affected_file,
3735 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433736
sergeyu34d21222015-09-16 00:11:443737 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433738 files = []
3739 for f in input_api.AffectedSourceFiles(FileFilter):
3740 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3741 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3742 contents = input_api.ReadFile(f)
3743 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243744 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433745 pattern.search(line)):
3746 files.append(f)
3747 break
3748
3749 if files:
yolandyandaabc6d2016-04-18 18:29:393750 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443751 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433752 'Please move them to an appropriate source file so that the ' +
3753 'template gets instantiated in a single compilation unit.',
3754 files) ]
3755 return []
3756
3757
[email protected]fd20b902014-05-09 02:14:533758_DEPRECATED_CSS = [
3759 # Values
3760 ( "-webkit-box", "flex" ),
3761 ( "-webkit-inline-box", "inline-flex" ),
3762 ( "-webkit-flex", "flex" ),
3763 ( "-webkit-inline-flex", "inline-flex" ),
3764 ( "-webkit-min-content", "min-content" ),
3765 ( "-webkit-max-content", "max-content" ),
3766
3767 # Properties
3768 ( "-webkit-background-clip", "background-clip" ),
3769 ( "-webkit-background-origin", "background-origin" ),
3770 ( "-webkit-background-size", "background-size" ),
3771 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443772 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533773
3774 # Functions
3775 ( "-webkit-gradient", "gradient" ),
3776 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3777 ( "-webkit-linear-gradient", "linear-gradient" ),
3778 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3779 ( "-webkit-radial-gradient", "radial-gradient" ),
3780 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3781]
3782
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203783
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493784# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363785def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533786 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253787 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343788 documentation and iOS CSS for dom distiller
3789 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253790 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533791 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493792 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443793 files_to_skip = (_EXCLUDED_PATHS +
3794 _TEST_CODE_EXCLUDED_PATHS +
3795 input_api.DEFAULT_FILES_TO_SKIP +
3796 (r"^chrome/common/extensions/docs",
3797 r"^chrome/docs",
3798 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3799 r"^components/neterror/resources/neterror.css",
3800 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253801 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443802 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533803 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3804 for line_num, line in fpath.ChangedContents():
3805 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023806 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533807 results.append(output_api.PresubmitError(
3808 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3809 (fpath.LocalPath(), line_num, deprecated_value, value)))
3810 return results
3811
mohan.reddyf21db962014-10-16 12:26:473812
Saagar Sanghavifceeaae2020-08-12 16:40:363813def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363814 bad_files = {}
3815 for f in input_api.AffectedFiles(include_deletes=False):
3816 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493817 not f.LocalPath().startswith('third_party/blink') and
3818 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363819 continue
3820
Daniel Bratell65b033262019-04-23 08:17:063821 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363822 continue
3823
Vaclav Brozekd5de76a2018-03-17 07:57:503824 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363825 if "#include" in line and "../" in line]
3826 if not relative_includes:
3827 continue
3828 bad_files[f.LocalPath()] = relative_includes
3829
3830 if not bad_files:
3831 return []
3832
3833 error_descriptions = []
3834 for file_path, bad_lines in bad_files.iteritems():
3835 error_description = file_path
3836 for line in bad_lines:
3837 error_description += '\n ' + line
3838 error_descriptions.append(error_description)
3839
3840 results = []
3841 results.append(output_api.PresubmitError(
3842 'You added one or more relative #include paths (including "../").\n'
3843 'These shouldn\'t be used because they can be used to include headers\n'
3844 'from code that\'s not correctly specified as a dependency in the\n'
3845 'relevant BUILD.gn file(s).',
3846 error_descriptions))
3847
3848 return results
3849
Takeshi Yoshinoe387aa32017-08-02 13:16:133850
Saagar Sanghavifceeaae2020-08-12 16:40:363851def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063852 """Check that nobody tries to include a cc file. It's a relatively
3853 common error which results in duplicate symbols in object
3854 files. This may not always break the build until someone later gets
3855 very confusing linking errors."""
3856 results = []
3857 for f in input_api.AffectedFiles(include_deletes=False):
3858 # We let third_party code do whatever it wants
3859 if (f.LocalPath().startswith('third_party') and
3860 not f.LocalPath().startswith('third_party/blink') and
3861 not f.LocalPath().startswith('third_party\\blink')):
3862 continue
3863
3864 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3865 continue
3866
3867 for _, line in f.ChangedContents():
3868 if line.startswith('#include "'):
3869 included_file = line.split('"')[1]
3870 if _IsCPlusPlusFile(input_api, included_file):
3871 # The most common naming for external files with C++ code,
3872 # apart from standard headers, is to call them foo.inc, but
3873 # Chromium sometimes uses foo-inc.cc so allow that as well.
3874 if not included_file.endswith(('.h', '-inc.cc')):
3875 results.append(output_api.PresubmitError(
3876 'Only header files or .inc files should be included in other\n'
3877 'C++ files. Compiling the contents of a cc file more than once\n'
3878 'will cause duplicate information in the build which may later\n'
3879 'result in strange link_errors.\n' +
3880 f.LocalPath() + ':\n ' +
3881 line))
3882
3883 return results
3884
3885
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203886def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3887 if not isinstance(key, ast.Str):
3888 return 'Key at line %d must be a string literal' % key.lineno
3889 if not isinstance(value, ast.Dict):
3890 return 'Value at line %d must be a dict' % value.lineno
3891 if len(value.keys) != 1:
3892 return 'Dict at line %d must have single entry' % value.lineno
3893 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3894 return (
3895 'Entry at line %d must have a string literal \'filepath\' as key' %
3896 value.lineno)
3897 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133898
Takeshi Yoshinoe387aa32017-08-02 13:16:133899
Sergey Ulanov4af16052018-11-08 02:41:463900def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203901 if not isinstance(key, ast.Str):
3902 return 'Key at line %d must be a string literal' % key.lineno
3903 if not isinstance(value, ast.List):
3904 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463905 for element in value.elts:
3906 if not isinstance(element, ast.Str):
3907 return 'Watchlist elements on line %d is not a string' % key.lineno
3908 if not email_regex.match(element.s):
3909 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3910 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203911 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133912
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Sergey Ulanov4af16052018-11-08 02:41:463914def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203915 mismatch_template = (
3916 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3917 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133918
Sergey Ulanov4af16052018-11-08 02:41:463919 email_regex = input_api.re.compile(
3920 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3921
3922 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203923 i = 0
3924 last_key = ''
3925 while True:
3926 if i >= len(wd_dict.keys):
3927 if i >= len(w_dict.keys):
3928 return None
3929 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3930 elif i >= len(w_dict.keys):
3931 return (
3932 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133933
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203934 wd_key = wd_dict.keys[i]
3935 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133936
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203937 result = _CheckWatchlistDefinitionsEntrySyntax(
3938 wd_key, wd_dict.values[i], ast)
3939 if result is not None:
3940 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133941
Sergey Ulanov4af16052018-11-08 02:41:463942 result = _CheckWatchlistsEntrySyntax(
3943 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203944 if result is not None:
3945 return 'Bad entry in WATCHLISTS dict: %s' % result
3946
3947 if wd_key.s != w_key.s:
3948 return mismatch_template % (
3949 '%s at line %d' % (wd_key.s, wd_key.lineno),
3950 '%s at line %d' % (w_key.s, w_key.lineno))
3951
3952 if wd_key.s < last_key:
3953 return (
3954 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3955 (wd_key.lineno, w_key.lineno))
3956 last_key = wd_key.s
3957
3958 i = i + 1
3959
3960
Sergey Ulanov4af16052018-11-08 02:41:463961def _CheckWATCHLISTSSyntax(expression, input_api):
3962 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203963 if not isinstance(expression, ast.Expression):
3964 return 'WATCHLISTS file must contain a valid expression'
3965 dictionary = expression.body
3966 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3967 return 'WATCHLISTS file must have single dict with exactly two entries'
3968
3969 first_key = dictionary.keys[0]
3970 first_value = dictionary.values[0]
3971 second_key = dictionary.keys[1]
3972 second_value = dictionary.values[1]
3973
3974 if (not isinstance(first_key, ast.Str) or
3975 first_key.s != 'WATCHLIST_DEFINITIONS' or
3976 not isinstance(first_value, ast.Dict)):
3977 return (
3978 'The first entry of the dict in WATCHLISTS file must be '
3979 'WATCHLIST_DEFINITIONS dict')
3980
3981 if (not isinstance(second_key, ast.Str) or
3982 second_key.s != 'WATCHLISTS' or
3983 not isinstance(second_value, ast.Dict)):
3984 return (
3985 'The second entry of the dict in WATCHLISTS file must be '
3986 'WATCHLISTS dict')
3987
Sergey Ulanov4af16052018-11-08 02:41:463988 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133989
3990
Saagar Sanghavifceeaae2020-08-12 16:40:363991def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133992 for f in input_api.AffectedFiles(include_deletes=False):
3993 if f.LocalPath() == 'WATCHLISTS':
3994 contents = input_api.ReadFile(f, 'r')
3995
3996 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203997 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133998 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203999 # Get an AST tree for it and scan the tree for detailed style checking.
4000 expression = input_api.ast.parse(
4001 contents, filename='WATCHLISTS', mode='eval')
4002 except ValueError as e:
4003 return [output_api.PresubmitError(
4004 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4005 except SyntaxError as e:
4006 return [output_api.PresubmitError(
4007 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4008 except TypeError as e:
4009 return [output_api.PresubmitError(
4010 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134011
Sergey Ulanov4af16052018-11-08 02:41:464012 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204013 if result is not None:
4014 return [output_api.PresubmitError(result)]
4015 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134016
4017 return []
4018
4019
Andrew Grieve1b290e4a22020-11-24 20:07:014020def CheckGnGlobForward(input_api, output_api):
4021 """Checks that forward_variables_from(invoker, "*") follows best practices.
4022
4023 As documented at //build/docs/writing_gn_templates.md
4024 """
4025 def gn_files(f):
4026 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
4027
4028 problems = []
4029 for f in input_api.AffectedSourceFiles(gn_files):
4030 for line_num, line in f.ChangedContents():
4031 if 'forward_variables_from(invoker, "*")' in line:
4032 problems.append(
4033 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4034 f.LocalPath(), line_num))
4035
4036 if problems:
4037 return [output_api.PresubmitPromptWarning(
4038 'forward_variables_from("*") without exclusions',
4039 items=sorted(problems),
4040 long_text=('The variables "visibilty" and "test_only" should be '
4041 'explicitly listed in forward_variables_from(). For more '
4042 'details, see:\n'
4043 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4044 'build/docs/writing_gn_templates.md'
4045 '#Using-forward_variables_from'))]
4046 return []
4047
4048
Saagar Sanghavifceeaae2020-08-12 16:40:364049def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194050 """Checks that newly added header files have corresponding GN changes.
4051 Note that this is only a heuristic. To be precise, run script:
4052 build/check_gn_headers.py.
4053 """
4054
4055 def headers(f):
4056 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444057 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194058
4059 new_headers = []
4060 for f in input_api.AffectedSourceFiles(headers):
4061 if f.Action() != 'A':
4062 continue
4063 new_headers.append(f.LocalPath())
4064
4065 def gn_files(f):
James Cook24a504192020-07-23 00:08:444066 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194067
4068 all_gn_changed_contents = ''
4069 for f in input_api.AffectedSourceFiles(gn_files):
4070 for _, line in f.ChangedContents():
4071 all_gn_changed_contents += line
4072
4073 problems = []
4074 for header in new_headers:
4075 basename = input_api.os_path.basename(header)
4076 if basename not in all_gn_changed_contents:
4077 problems.append(header)
4078
4079 if problems:
4080 return [output_api.PresubmitPromptWarning(
4081 'Missing GN changes for new header files', items=sorted(problems),
4082 long_text='Please double check whether newly added header files need '
4083 'corresponding changes in gn or gni files.\nThis checking is only a '
4084 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4085 'Read https://crbug.com/661774 for more info.')]
4086 return []
4087
4088
Saagar Sanghavifceeaae2020-08-12 16:40:364089def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024090 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4091
4092 This assumes we won't intentionally reference one product from the other
4093 product.
4094 """
4095 all_problems = []
4096 test_cases = [{
4097 "filename_postfix": "google_chrome_strings.grd",
4098 "correct_name": "Chrome",
4099 "incorrect_name": "Chromium",
4100 }, {
4101 "filename_postfix": "chromium_strings.grd",
4102 "correct_name": "Chromium",
4103 "incorrect_name": "Chrome",
4104 }]
4105
4106 for test_case in test_cases:
4107 problems = []
4108 filename_filter = lambda x: x.LocalPath().endswith(
4109 test_case["filename_postfix"])
4110
4111 # Check each new line. Can yield false positives in multiline comments, but
4112 # easier than trying to parse the XML because messages can have nested
4113 # children, and associating message elements with affected lines is hard.
4114 for f in input_api.AffectedSourceFiles(filename_filter):
4115 for line_num, line in f.ChangedContents():
4116 if "<message" in line or "<!--" in line or "-->" in line:
4117 continue
4118 if test_case["incorrect_name"] in line:
4119 problems.append(
4120 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4121
4122 if problems:
4123 message = (
4124 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4125 % (test_case["correct_name"], test_case["correct_name"],
4126 test_case["incorrect_name"]))
4127 all_problems.append(
4128 output_api.PresubmitPromptWarning(message, items=problems))
4129
4130 return all_problems
4131
4132
Saagar Sanghavifceeaae2020-08-12 16:40:364133def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514134 # TODO(crbug.com/941824): We need to make sure the entries in
4135 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4136 # so that users of //buildtools in other projects get the same tooling
4137 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4138 # support to gclient, we can eliminate the duplication and delete
4139 # this presubmit check.
4140
4141 # Update this regexp if new revisions are added to the files.
4142 rev_regexp = input_api.re.compile(
Nico Weberff3d9b362021-03-04 02:57:594143 ("'(clang_format_revision|gn_version)':"))
Dirk Pranke3c18a382019-03-15 01:07:514144
4145 # If a user is changing one revision, they need to change the same
4146 # line in both files. This means that any given change should contain
4147 # exactly the same list of changed lines that match the regexps. The
4148 # replace(' ', '') call allows us to ignore whitespace changes to the
4149 # lines. The 'long_text' parameter to the error will contain the
4150 # list of changed lines in both files, which should make it easy enough
4151 # to spot the error without going overboard in this implementation.
Ola Rozenfeld355a1b4e2021-01-26 03:41:574152 buildtools_deps = input_api.os_path.join('buildtools', 'DEPS')
Dirk Pranke3c18a382019-03-15 01:07:514153 revs_changes = {
4154 'DEPS': {},
Ola Rozenfeld355a1b4e2021-01-26 03:41:574155 buildtools_deps: {},
Dirk Pranke3c18a382019-03-15 01:07:514156 }
4157 long_text = ''
4158
4159 for f in input_api.AffectedFiles(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574160 file_filter=lambda f: f.LocalPath() in ('DEPS', buildtools_deps)):
Dirk Pranke3c18a382019-03-15 01:07:514161 for line_num, line in f.ChangedContents():
4162 if rev_regexp.search(line):
4163 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4164 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4165
Ola Rozenfeld355a1b4e2021-01-26 03:41:574166 if set(revs_changes['DEPS']) != set(revs_changes[buildtools_deps]):
Dirk Pranke3c18a382019-03-15 01:07:514167 return [output_api.PresubmitError(
Ola Rozenfeld355a1b4e2021-01-26 03:41:574168 'Change buildtools revisions in sync in both DEPS and ' +
4169 buildtools_deps + '.', long_text=long_text + '\n')]
Dirk Pranke3c18a382019-03-15 01:07:514170 else:
4171 return []
4172
4173
Saagar Sanghavifceeaae2020-08-12 16:40:364174def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364175 """Avoid large files, especially binary files, in the repository since
4176 git doesn't scale well for those. They will be in everyone's repo
4177 clones forever, forever making Chromium slower to clone and work
4178 with."""
4179
4180 # Uploading files to cloud storage is not trivial so we don't want
4181 # to set the limit too low, but the upper limit for "normal" large
4182 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4183 # anything over 20 MB is exceptional.
4184 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4185
4186 too_large_files = []
4187 for f in input_api.AffectedFiles():
4188 # Check both added and modified files (but not deleted files).
4189 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384190 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364191 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4192 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4193
4194 if too_large_files:
4195 message = (
4196 'Do not commit large files to git since git scales badly for those.\n' +
4197 'Instead put the large files in cloud storage and use DEPS to\n' +
4198 'fetch them.\n' + '\n'.join(too_large_files)
4199 )
4200 return [output_api.PresubmitError(
4201 'Too large files found in commit', long_text=message + '\n')]
4202 else:
4203 return []
4204
Max Morozb47503b2019-08-08 21:03:274205
Saagar Sanghavifceeaae2020-08-12 16:40:364206def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274207 """Checks specific for fuzz target sources."""
4208 EXPORTED_SYMBOLS = [
4209 'LLVMFuzzerInitialize',
4210 'LLVMFuzzerCustomMutator',
4211 'LLVMFuzzerCustomCrossOver',
4212 'LLVMFuzzerMutate',
4213 ]
4214
4215 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4216
4217 def FilterFile(affected_file):
4218 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444219 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4220 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274221
4222 return input_api.FilterSourceFile(
4223 affected_file,
James Cook24a504192020-07-23 00:08:444224 files_to_check=[files_to_check],
4225 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274226
4227 files_with_missing_header = []
4228 for f in input_api.AffectedSourceFiles(FilterFile):
4229 contents = input_api.ReadFile(f, 'r')
4230 if REQUIRED_HEADER in contents:
4231 continue
4232
4233 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4234 files_with_missing_header.append(f.LocalPath())
4235
4236 if not files_with_missing_header:
4237 return []
4238
4239 long_text = (
4240 'If you define any of the libFuzzer optional functions (%s), it is '
4241 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4242 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4243 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4244 'to access command line arguments passed to the fuzzer. Instead, prefer '
4245 'static initialization and shared resources as documented in '
4246 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4247 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4248 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4249 )
4250
4251 return [output_api.PresubmitPromptWarning(
4252 message="Missing '%s' in:" % REQUIRED_HEADER,
4253 items=files_with_missing_header,
4254 long_text=long_text)]
4255
4256
Mohamed Heikald048240a2019-11-12 16:57:374257def _CheckNewImagesWarning(input_api, output_api):
4258 """
4259 Warns authors who add images into the repo to make sure their images are
4260 optimized before committing.
4261 """
4262 images_added = False
4263 image_paths = []
4264 errors = []
4265 filter_lambda = lambda x: input_api.FilterSourceFile(
4266 x,
James Cook24a504192020-07-23 00:08:444267 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4268 + input_api.DEFAULT_FILES_TO_SKIP),
4269 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374270 )
4271 for f in input_api.AffectedFiles(
4272 include_deletes=False, file_filter=filter_lambda):
4273 local_path = f.LocalPath().lower()
4274 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4275 images_added = True
4276 image_paths.append(f)
4277 if images_added:
4278 errors.append(output_api.PresubmitPromptWarning(
4279 'It looks like you are trying to commit some images. If these are '
4280 'non-test-only images, please make sure to read and apply the tips in '
4281 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4282 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4283 'FYI only and will not block your CL on the CQ.', image_paths))
4284 return errors
4285
4286
Saagar Sanghavifceeaae2020-08-12 16:40:364287def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574288 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224289 results = []
dgnaa68d5e2015-06-10 10:08:224290 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174291 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224292 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294293 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064294 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4295 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424296 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184297 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574298 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374299 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154300 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574301 return results
4302
Saagar Sanghavifceeaae2020-08-12 16:40:364303def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574304 """Groups commit checks that target android code."""
4305 results = []
4306 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224307 return results
4308
Chris Hall59f8d0c72020-05-01 07:31:194309# TODO(chrishall): could we additionally match on any path owned by
4310# ui/accessibility/OWNERS ?
4311_ACCESSIBILITY_PATHS = (
4312 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4313 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4314 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4315 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4316 r"^content[\\/]browser[\\/]accessibility[\\/]",
4317 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4318 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4319 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4320 r"^ui[\\/]accessibility[\\/]",
4321 r"^ui[\\/]views[\\/]accessibility[\\/]",
4322)
4323
Saagar Sanghavifceeaae2020-08-12 16:40:364324def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194325 """Checks that commits to accessibility code contain an AX-Relnotes field in
4326 their commit message."""
4327 def FileFilter(affected_file):
4328 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444329 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194330
4331 # Only consider changes affecting accessibility paths.
4332 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4333 return []
4334
Akihiro Ota08108e542020-05-20 15:30:534335 # AX-Relnotes can appear in either the description or the footer.
4336 # When searching the description, require 'AX-Relnotes:' to appear at the
4337 # beginning of a line.
4338 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4339 description_has_relnotes = any(ax_regex.match(line)
4340 for line in input_api.change.DescriptionText().lower().splitlines())
4341
4342 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4343 'AX-Relnotes', [])
4344 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194345 return []
4346
4347 # TODO(chrishall): link to Relnotes documentation in message.
4348 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4349 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4350 "user-facing changes"
4351 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4352 "user-facing effects"
4353 "\n if this is confusing or annoying then please contact members "
4354 "of ui/accessibility/OWNERS.")
4355
4356 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224357
Saagar Sanghavifceeaae2020-08-12 16:40:364358def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394359 """Checks common to both upload and commit."""
4360 results = []
4361 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384362 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544363 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084364
4365 author = input_api.change.author_email
4366 if author and author not in _KNOWN_ROBOTS:
4367 results.extend(
4368 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4369
[email protected]9f919cc2013-07-31 03:04:044370 results.extend(
4371 input_api.canned_checks.CheckChangeHasNoTabs(
4372 input_api,
4373 output_api,
4374 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434375 results.extend(input_api.RunTests(
4376 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244377
Edward Lesmesce51df52020-08-04 22:10:174378 dirmd_bin = input_api.os_path.join(
4379 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4380 results.extend(input_api.RunTests(
4381 input_api.canned_checks.CheckDirMetadataFormat(
4382 input_api, output_api, dirmd_bin)))
4383 results.extend(
4384 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4385 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554386 results.extend(
4387 input_api.canned_checks.CheckNoNewMetadataInOwners(
4388 input_api, output_api))
Edward Lesmesce51df52020-08-04 22:10:174389
Vaclav Brozekcdc7defb2018-03-20 09:54:354390 for f in input_api.AffectedFiles():
4391 path, name = input_api.os_path.split(f.LocalPath())
4392 if name == 'PRESUBMIT.py':
4393 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004394 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4395 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074396 # The PRESUBMIT.py file (and the directory containing it) might
4397 # have been affected by being moved or removed, so only try to
4398 # run the tests if they still exist.
4399 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4400 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444401 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394402 return results
[email protected]1f7b4172010-01-28 01:17:344403
[email protected]b337cb5b2011-01-23 21:24:054404
Saagar Sanghavifceeaae2020-08-12 16:40:364405def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494406 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4407 if f.LocalPath().endswith(('.orig', '.rej'))]
4408 if problems:
4409 return [output_api.PresubmitError(
4410 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034411 else:
4412 return []
[email protected]b8079ae4a2012-12-05 19:56:494413
4414
Saagar Sanghavifceeaae2020-08-12 16:40:364415def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214416 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4417 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4418 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074419 include_re = input_api.re.compile(
4420 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4421 extension_re = input_api.re.compile(r'\.[a-z]+$')
4422 errors = []
4423 for f in input_api.AffectedFiles():
4424 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4425 continue
4426 found_line_number = None
4427 found_macro = None
4428 for line_num, line in f.ChangedContents():
4429 match = macro_re.search(line)
4430 if match:
4431 found_line_number = line_num
4432 found_macro = match.group(2)
4433 break
4434 if not found_line_number:
4435 continue
4436
4437 found_include = False
4438 for line in f.NewContents():
4439 if include_re.search(line):
4440 found_include = True
4441 break
4442 if found_include:
4443 continue
4444
4445 if not f.LocalPath().endswith('.h'):
4446 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4447 try:
4448 content = input_api.ReadFile(primary_header_path, 'r')
4449 if include_re.search(content):
4450 continue
4451 except IOError:
4452 pass
4453 errors.append('%s:%d %s macro is used without including build/'
4454 'build_config.h.'
4455 % (f.LocalPath(), found_line_number, found_macro))
4456 if errors:
4457 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4458 return []
4459
4460
[email protected]b00342e7f2013-03-26 16:21:544461def _DidYouMeanOSMacro(bad_macro):
4462 try:
4463 return {'A': 'OS_ANDROID',
4464 'B': 'OS_BSD',
4465 'C': 'OS_CHROMEOS',
4466 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444467 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544468 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444469 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544470 'N': 'OS_NACL',
4471 'O': 'OS_OPENBSD',
4472 'P': 'OS_POSIX',
4473 'S': 'OS_SOLARIS',
4474 'W': 'OS_WIN'}[bad_macro[3].upper()]
4475 except KeyError:
4476 return ''
4477
4478
4479def _CheckForInvalidOSMacrosInFile(input_api, f):
4480 """Check for sensible looking, totally invalid OS macros."""
4481 preprocessor_statement = input_api.re.compile(r'^\s*#')
4482 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4483 results = []
4484 for lnum, line in f.ChangedContents():
4485 if preprocessor_statement.search(line):
4486 for match in os_macro.finditer(line):
4487 if not match.group(1) in _VALID_OS_MACROS:
4488 good = _DidYouMeanOSMacro(match.group(1))
4489 did_you_mean = ' (did you mean %s?)' % good if good else ''
4490 results.append(' %s:%d %s%s' % (f.LocalPath(),
4491 lnum,
4492 match.group(1),
4493 did_you_mean))
4494 return results
4495
4496
Saagar Sanghavifceeaae2020-08-12 16:40:364497def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544498 """Check all affected files for invalid OS macros."""
4499 bad_macros = []
tzik3f295992018-12-04 20:32:234500 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474501 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544502 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4503
4504 if not bad_macros:
4505 return []
4506
4507 return [output_api.PresubmitError(
4508 'Possibly invalid OS macro[s] found. Please fix your code\n'
4509 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4510
lliabraa35bab3932014-10-01 12:16:444511
4512def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4513 """Check all affected files for invalid "if defined" macros."""
4514 ALWAYS_DEFINED_MACROS = (
4515 "TARGET_CPU_PPC",
4516 "TARGET_CPU_PPC64",
4517 "TARGET_CPU_68K",
4518 "TARGET_CPU_X86",
4519 "TARGET_CPU_ARM",
4520 "TARGET_CPU_MIPS",
4521 "TARGET_CPU_SPARC",
4522 "TARGET_CPU_ALPHA",
4523 "TARGET_IPHONE_SIMULATOR",
4524 "TARGET_OS_EMBEDDED",
4525 "TARGET_OS_IPHONE",
4526 "TARGET_OS_MAC",
4527 "TARGET_OS_UNIX",
4528 "TARGET_OS_WIN32",
4529 )
4530 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4531 results = []
4532 for lnum, line in f.ChangedContents():
4533 for match in ifdef_macro.finditer(line):
4534 if match.group(1) in ALWAYS_DEFINED_MACROS:
4535 always_defined = ' %s is always defined. ' % match.group(1)
4536 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4537 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4538 lnum,
4539 always_defined,
4540 did_you_mean))
4541 return results
4542
4543
Saagar Sanghavifceeaae2020-08-12 16:40:364544def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444545 """Check all affected files for invalid "if defined" macros."""
4546 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054547 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444548 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054549 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214550 continue
lliabraa35bab3932014-10-01 12:16:444551 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4552 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4553
4554 if not bad_macros:
4555 return []
4556
4557 return [output_api.PresubmitError(
4558 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4559 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4560 bad_macros)]
4561
4562
Saagar Sanghavifceeaae2020-08-12 16:40:364563def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044564 """Check for same IPC rules described in
4565 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4566 """
4567 base_pattern = r'IPC_ENUM_TRAITS\('
4568 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4569 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4570
4571 problems = []
4572 for f in input_api.AffectedSourceFiles(None):
4573 local_path = f.LocalPath()
4574 if not local_path.endswith('.h'):
4575 continue
4576 for line_number, line in f.ChangedContents():
4577 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4578 problems.append(
4579 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4580
4581 if problems:
4582 return [output_api.PresubmitPromptWarning(
4583 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4584 else:
4585 return []
4586
[email protected]b00342e7f2013-03-26 16:21:544587
Saagar Sanghavifceeaae2020-08-12 16:40:364588def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054589 """Check to make sure no files being submitted have long paths.
4590 This causes issues on Windows.
4591 """
4592 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194593 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054594 local_path = f.LocalPath()
4595 # Windows has a path limit of 260 characters. Limit path length to 200 so
4596 # that we have some extra for the prefix on dev machines and the bots.
4597 if len(local_path) > 200:
4598 problems.append(local_path)
4599
4600 if problems:
4601 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4602 else:
4603 return []
4604
4605
Saagar Sanghavifceeaae2020-08-12 16:40:364606def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144607 """Check that header files have proper guards against multiple inclusion.
4608 If a file should not have such guards (and it probably should) then it
4609 should include the string "no-include-guard-because-multiply-included".
4610 """
Daniel Bratell6a75baef62018-06-04 10:04:454611 def is_chromium_header_file(f):
4612 # We only check header files under the control of the Chromium
4613 # project. That is, those outside third_party apart from
4614 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324615 # We also exclude *_message_generator.h headers as they use
4616 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454617 file_with_path = input_api.os_path.normpath(f.LocalPath())
4618 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324619 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454620 (not file_with_path.startswith('third_party') or
4621 file_with_path.startswith(
4622 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144623
4624 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344625 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144626
4627 errors = []
4628
Daniel Bratell6a75baef62018-06-04 10:04:454629 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144630 guard_name = None
4631 guard_line_number = None
4632 seen_guard_end = False
4633
4634 file_with_path = input_api.os_path.normpath(f.LocalPath())
4635 base_file_name = input_api.os_path.splitext(
4636 input_api.os_path.basename(file_with_path))[0]
4637 upper_base_file_name = base_file_name.upper()
4638
4639 expected_guard = replace_special_with_underscore(
4640 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144641
4642 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574643 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4644 # are too many (1000+) files with slight deviations from the
4645 # coding style. The most important part is that the include guard
4646 # is there, and that it's unique, not the name so this check is
4647 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144648 #
4649 # As code becomes more uniform, this could be made stricter.
4650
4651 guard_name_pattern_list = [
4652 # Anything with the right suffix (maybe with an extra _).
4653 r'\w+_H__?',
4654
Daniel Bratell39b5b062018-05-16 18:09:574655 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144656 r'\w+_h',
4657
4658 # Anything including the uppercase name of the file.
4659 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4660 upper_base_file_name)) + r'\w*',
4661 ]
4662 guard_name_pattern = '|'.join(guard_name_pattern_list)
4663 guard_pattern = input_api.re.compile(
4664 r'#ifndef\s+(' + guard_name_pattern + ')')
4665
4666 for line_number, line in enumerate(f.NewContents()):
4667 if 'no-include-guard-because-multiply-included' in line:
4668 guard_name = 'DUMMY' # To not trigger check outside the loop.
4669 break
4670
4671 if guard_name is None:
4672 match = guard_pattern.match(line)
4673 if match:
4674 guard_name = match.group(1)
4675 guard_line_number = line_number
4676
Daniel Bratell39b5b062018-05-16 18:09:574677 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454678 # don't match the chromium style guide, but new files should
4679 # get it right.
4680 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574681 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144682 errors.append(output_api.PresubmitPromptWarning(
4683 'Header using the wrong include guard name %s' % guard_name,
4684 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574685 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144686 else:
4687 # The line after #ifndef should have a #define of the same name.
4688 if line_number == guard_line_number + 1:
4689 expected_line = '#define %s' % guard_name
4690 if line != expected_line:
4691 errors.append(output_api.PresubmitPromptWarning(
4692 'Missing "%s" for include guard' % expected_line,
4693 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4694 'Expected: %r\nGot: %r' % (expected_line, line)))
4695
4696 if not seen_guard_end and line == '#endif // %s' % guard_name:
4697 seen_guard_end = True
4698 elif seen_guard_end:
4699 if line.strip() != '':
4700 errors.append(output_api.PresubmitPromptWarning(
4701 'Include guard %s not covering the whole file' % (
4702 guard_name), [f.LocalPath()]))
4703 break # Nothing else to check and enough to warn once.
4704
4705 if guard_name is None:
4706 errors.append(output_api.PresubmitPromptWarning(
4707 'Missing include guard %s' % expected_guard,
4708 [f.LocalPath()],
4709 'Missing include guard in %s\n'
4710 'Recommended name: %s\n'
4711 'This check can be disabled by having the string\n'
4712 'no-include-guard-because-multiply-included in the header.' %
4713 (f.LocalPath(), expected_guard)))
4714
4715 return errors
4716
4717
Saagar Sanghavifceeaae2020-08-12 16:40:364718def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234719 """Check source code and known ascii text files for Windows style line
4720 endings.
4721 """
earthdok1b5e0ee2015-03-10 15:19:104722 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234723
4724 file_inclusion_pattern = (
4725 known_text_files,
4726 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4727 )
4728
mostynbb639aca52015-01-07 20:31:234729 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534730 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444731 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534732 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504733 include_file = False
4734 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234735 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504736 include_file = True
4737 if include_file:
4738 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234739
4740 if problems:
4741 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4742 'these files to contain Windows style line endings?\n' +
4743 '\n'.join(problems))]
4744
4745 return []
4746
4747
Saagar Sanghavifceeaae2020-08-12 16:40:364748def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134749 """Checks that all source files use SYSLOG properly."""
4750 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364751 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564752 for line_number, line in f.ChangedContents():
4753 if 'SYSLOG' in line:
4754 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4755
pastarmovj89f7ee12016-09-20 14:58:134756 if syslog_files:
4757 return [output_api.PresubmitPromptWarning(
4758 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4759 ' calls.\nFiles to check:\n', items=syslog_files)]
4760 return []
4761
4762
[email protected]1f7b4172010-01-28 01:17:344763def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364764 if input_api.version < [2, 0, 0]:
4765 return [output_api.PresubmitError("Your depot_tools is out of date. "
4766 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4767 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344768 results = []
scottmg39b29952014-12-08 18:31:284769 results.extend(
jam93a6ee792017-02-08 23:59:224770 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544771 return results
[email protected]ca8d1982009-02-19 16:33:124772
4773
[email protected]1bfb8322014-04-23 01:02:414774def GetTryServerMasterForBot(bot):
4775 """Returns the Try Server master for the given bot.
4776
[email protected]0bb112362014-07-26 04:38:324777 It tries to guess the master from the bot name, but may still fail
4778 and return None. There is no longer a default master.
4779 """
4780 # Potentially ambiguous bot names are listed explicitly.
4781 master_map = {
tandriie5587792016-07-14 00:34:504782 'chromium_presubmit': 'master.tryserver.chromium.linux',
4783 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414784 }
[email protected]0bb112362014-07-26 04:38:324785 master = master_map.get(bot)
4786 if not master:
wnwen4fbaab82016-05-25 12:54:364787 if 'android' in bot:
tandriie5587792016-07-14 00:34:504788 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364789 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504790 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324791 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504792 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324793 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504794 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324795 return master
[email protected]1bfb8322014-04-23 01:02:414796
4797
[email protected]ca8d1982009-02-19 16:33:124798def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364799 if input_api.version < [2, 0, 0]:
4800 return [output_api.PresubmitError("Your depot_tools is out of date. "
4801 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4802 "but your version is %d.%d.%d" % tuple(input_api.version))]
4803
[email protected]fe5f57c52009-06-05 14:25:544804 results = []
[email protected]fe5f57c52009-06-05 14:25:544805 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274806 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344807 input_api,
4808 output_api,
[email protected]2fdd1f362013-01-16 03:56:034809 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274810
jam93a6ee792017-02-08 23:59:224811 results.extend(
4812 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544813 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4814 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384815 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4816 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414817 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4818 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544819 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144820
4821
Saagar Sanghavifceeaae2020-08-12 16:40:364822def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264823 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024824 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4825 # footer is set to true.
4826 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264827 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024828 footer.lower()
4829 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264830 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024831
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144832 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264833 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144834 import sys
4835 from io import StringIO
4836
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144837 new_or_added_paths = set(f.LocalPath()
4838 for f in input_api.AffectedFiles()
4839 if (f.Action() == 'A' or f.Action() == 'M'))
4840 removed_paths = set(f.LocalPath()
4841 for f in input_api.AffectedFiles(include_deletes=True)
4842 if f.Action() == 'D')
4843
Andrew Grieve0e8790c2020-09-03 17:27:324844 affected_grds = [
4845 f for f in input_api.AffectedFiles()
4846 if f.LocalPath().endswith(('.grd', '.grdp'))
4847 ]
4848 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164849 if not affected_grds:
4850 return []
4851
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144852 affected_png_paths = [f.AbsoluteLocalPath()
4853 for f in input_api.AffectedFiles()
4854 if (f.LocalPath().endswith('.png'))]
4855
4856 # Check for screenshots. Developers can upload screenshots using
4857 # tools/translation/upload_screenshots.py which finds and uploads
4858 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4859 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4860 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4861 #
4862 # The logic here is as follows:
4863 #
4864 # - If the CL has a .png file under the screenshots directory for a grd
4865 # file, warn the developer. Actual images should never be checked into the
4866 # Chrome repo.
4867 #
4868 # - If the CL contains modified or new messages in grd files and doesn't
4869 # contain the corresponding .sha1 files, warn the developer to add images
4870 # and upload them via tools/translation/upload_screenshots.py.
4871 #
4872 # - If the CL contains modified or new messages in grd files and the
4873 # corresponding .sha1 files, everything looks good.
4874 #
4875 # - If the CL contains removed messages in grd files but the corresponding
4876 # .sha1 files aren't removed, warn the developer to remove them.
4877 unnecessary_screenshots = []
4878 missing_sha1 = []
4879 unnecessary_sha1_files = []
4880
Rainhard Findlingfc31844c52020-05-15 09:58:264881 # This checks verifies that the ICU syntax of messages this CL touched is
4882 # valid, and reports any found syntax errors.
4883 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4884 # without developers being aware of them. Later on, such ICU syntax errors
4885 # break message extraction for translation, hence would block Chromium
4886 # translations until they are fixed.
4887 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144888
4889 def _CheckScreenshotAdded(screenshots_dir, message_id):
4890 sha1_path = input_api.os_path.join(
4891 screenshots_dir, message_id + '.png.sha1')
4892 if sha1_path not in new_or_added_paths:
4893 missing_sha1.append(sha1_path)
4894
4895
4896 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4897 sha1_path = input_api.os_path.join(
4898 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034899 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144900 unnecessary_sha1_files.append(sha1_path)
4901
Rainhard Findlingfc31844c52020-05-15 09:58:264902
4903 def _ValidateIcuSyntax(text, level, signatures):
4904 """Validates ICU syntax of a text string.
4905
4906 Check if text looks similar to ICU and checks for ICU syntax correctness
4907 in this case. Reports various issues with ICU syntax and values of
4908 variants. Supports checking of nested messages. Accumulate information of
4909 each ICU messages found in the text for further checking.
4910
4911 Args:
4912 text: a string to check.
4913 level: a number of current nesting level.
4914 signatures: an accumulator, a list of tuple of (level, variable,
4915 kind, variants).
4916
4917 Returns:
4918 None if a string is not ICU or no issue detected.
4919 A tuple of (message, start index, end index) if an issue detected.
4920 """
4921 valid_types = {
4922 'plural': (frozenset(
4923 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4924 frozenset(['=1', 'other'])),
4925 'selectordinal': (frozenset(
4926 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4927 frozenset(['one', 'other'])),
4928 'select': (frozenset(), frozenset(['other'])),
4929 }
4930
4931 # Check if the message looks like an attempt to use ICU
4932 # plural. If yes - check if its syntax strictly matches ICU format.
4933 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4934 if not like:
4935 signatures.append((level, None, None, None))
4936 return
4937
4938 # Check for valid prefix and suffix
4939 m = re.match(
4940 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4941 r'(plural|selectordinal|select),\s*'
4942 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4943 if not m:
4944 return (('This message looks like an ICU plural, '
4945 'but does not follow ICU syntax.'), like.start(), like.end())
4946 starting, variable, kind, variant_pairs = m.groups()
4947 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4948 if depth:
4949 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4950 len(text))
4951 first = text[0]
4952 ending = text[last_pos:]
4953 if not starting:
4954 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4955 last_pos)
4956 if not ending or '}' not in ending:
4957 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4958 last_pos)
4959 elif first != '{':
4960 return (
4961 ('Invalid ICU format. Extra characters at the start of a complex '
4962 'message (go/icu-message-migration): "%s"') %
4963 starting, 0, len(starting))
4964 elif ending != '}':
4965 return (('Invalid ICU format. Extra characters at the end of a complex '
4966 'message (go/icu-message-migration): "%s"')
4967 % ending, last_pos - 1, len(text) - 1)
4968 if kind not in valid_types:
4969 return (('Unknown ICU message type %s. '
4970 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4971 known, required = valid_types[kind]
4972 defined_variants = set()
4973 for variant, variant_range, value, value_range in variants:
4974 start, end = variant_range
4975 if variant in defined_variants:
4976 return ('Variant "%s" is defined more than once' % variant,
4977 start, end)
4978 elif known and variant not in known:
4979 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4980 start, end)
4981 defined_variants.add(variant)
4982 # Check for nested structure
4983 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
4984 if res:
4985 return (res[0], res[1] + value_range[0] + 1,
4986 res[2] + value_range[0] + 1)
4987 missing = required - defined_variants
4988 if missing:
4989 return ('Required variants missing: %s' % ', '.join(missing), 0,
4990 len(text))
4991 signatures.append((level, variable, kind, defined_variants))
4992
4993
4994 def _ParseIcuVariants(text, offset=0):
4995 """Parse variants part of ICU complex message.
4996
4997 Builds a tuple of variant names and values, as well as
4998 their offsets in the input string.
4999
5000 Args:
5001 text: a string to parse
5002 offset: additional offset to add to positions in the text to get correct
5003 position in the complete ICU string.
5004
5005 Returns:
5006 List of tuples, each tuple consist of four fields: variant name,
5007 variant name span (tuple of two integers), variant value, value
5008 span (tuple of two integers).
5009 """
5010 depth, start, end = 0, -1, -1
5011 variants = []
5012 key = None
5013 for idx, char in enumerate(text):
5014 if char == '{':
5015 if not depth:
5016 start = idx
5017 chunk = text[end + 1:start]
5018 key = chunk.strip()
5019 pos = offset + end + 1 + chunk.find(key)
5020 span = (pos, pos + len(key))
5021 depth += 1
5022 elif char == '}':
5023 if not depth:
5024 return variants, depth, offset + idx
5025 depth -= 1
5026 if not depth:
5027 end = idx
5028 variants.append((key, span, text[start:end + 1], (offset + start,
5029 offset + end + 1)))
5030 return variants, depth, offset + end + 1
5031
meacer8c0d3832019-12-26 21:46:165032 try:
5033 old_sys_path = sys.path
5034 sys.path = sys.path + [input_api.os_path.join(
5035 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5036 from helper import grd_helper
5037 finally:
5038 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145039
5040 for f in affected_grds:
5041 file_path = f.LocalPath()
5042 old_id_to_msg_map = {}
5043 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385044 # Note that this code doesn't check if the file has been deleted. This is
5045 # OK because it only uses the old and new file contents and doesn't load
5046 # the file via its path.
5047 # It's also possible that a file's content refers to a renamed or deleted
5048 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5049 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5050 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145051 if file_path.endswith('.grdp'):
5052 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585053 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395054 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145055 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585056 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395057 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145058 else:
meacerff8a9b62019-12-10 19:43:585059 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145060 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585061 old_id_to_msg_map = grd_helper.GetGrdMessages(
5062 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145063 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585064 new_id_to_msg_map = grd_helper.GetGrdMessages(
5065 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145066
Rainhard Findlingd8d04372020-08-13 13:30:095067 grd_name, ext = input_api.os_path.splitext(
5068 input_api.os_path.basename(file_path))
5069 screenshots_dir = input_api.os_path.join(
5070 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5071
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145072 # Compute added, removed and modified message IDs.
5073 old_ids = set(old_id_to_msg_map)
5074 new_ids = set(new_id_to_msg_map)
5075 added_ids = new_ids - old_ids
5076 removed_ids = old_ids - new_ids
5077 modified_ids = set([])
5078 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355079 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095080 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5081 # The message content itself changed. Require an updated screenshot.
5082 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355083 elif old_id_to_msg_map[key].attrs['meaning'] != \
5084 new_id_to_msg_map[key].attrs['meaning']:
5085 # The message meaning changed. Ensure there is a screenshot for it.
5086 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5087 if sha1_path not in new_or_added_paths and not \
5088 input_api.os_path.exists(sha1_path):
5089 # There is neither a previous screenshot nor is a new one added now.
5090 # Require a screenshot.
5091 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145092
Rainhard Findlingfc31844c52020-05-15 09:58:265093 if run_screenshot_check:
5094 # Check the screenshot directory for .png files. Warn if there is any.
5095 for png_path in affected_png_paths:
5096 if png_path.startswith(screenshots_dir):
5097 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145098
Rainhard Findlingfc31844c52020-05-15 09:58:265099 for added_id in added_ids:
5100 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145101
Rainhard Findlingfc31844c52020-05-15 09:58:265102 for modified_id in modified_ids:
5103 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145104
Rainhard Findlingfc31844c52020-05-15 09:58:265105 for removed_id in removed_ids:
5106 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5107
5108 # Check new and changed strings for ICU syntax errors.
5109 for key in added_ids.union(modified_ids):
5110 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5111 err = _ValidateIcuSyntax(msg, 0, [])
5112 if err is not None:
5113 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
5115 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265116 if run_screenshot_check:
5117 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005118 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265119 'Do not include actual screenshots in the changelist. Run '
5120 'tools/translate/upload_screenshots.py to upload them instead:',
5121 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122
Rainhard Findlingfc31844c52020-05-15 09:58:265123 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005124 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265125 'You are adding or modifying UI strings.\n'
5126 'To ensure the best translations, take screenshots of the relevant UI '
5127 '(https://g.co/chrome/translation) and add these files to your '
5128 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
Rainhard Findlingfc31844c52020-05-15 09:58:265130 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005131 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265132 'You removed strings associated with these files. Remove:',
5133 sorted(unnecessary_sha1_files)))
5134 else:
5135 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5136 'screenshots check.'))
5137
5138 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075139 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265140 'ICU syntax errors were found in the following strings (problems or '
5141 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145142
5143 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125144
5145
Saagar Sanghavifceeaae2020-08-12 16:40:365146def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125147 repo_root=None,
5148 translation_expectations_path=None,
5149 grd_files=None):
5150 import sys
5151 affected_grds = [f for f in input_api.AffectedFiles()
5152 if (f.LocalPath().endswith('.grd') or
5153 f.LocalPath().endswith('.grdp'))]
5154 if not affected_grds:
5155 return []
5156
5157 try:
5158 old_sys_path = sys.path
5159 sys.path = sys.path + [
5160 input_api.os_path.join(
5161 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5162 from helper import git_helper
5163 from helper import translation_helper
5164 finally:
5165 sys.path = old_sys_path
5166
5167 # Check that translation expectations can be parsed and we can get a list of
5168 # translatable grd files. |repo_root| and |translation_expectations_path| are
5169 # only passed by tests.
5170 if not repo_root:
5171 repo_root = input_api.PresubmitLocalPath()
5172 if not translation_expectations_path:
5173 translation_expectations_path = input_api.os_path.join(
5174 repo_root, 'tools', 'gritsettings',
5175 'translation_expectations.pyl')
5176 if not grd_files:
5177 grd_files = git_helper.list_grds_in_repository(repo_root)
5178
dpapad8e21b472020-10-23 17:15:035179 # Ignore bogus grd files used only for testing
5180 # ui/webui/resoucres/tools/generate_grd.py.
5181 ignore_path = input_api.os_path.join(
5182 'ui', 'webui', 'resources', 'tools', 'tests')
5183 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5184
Mustafa Emre Acer51f2f742020-03-09 19:41:125185 try:
5186 translation_helper.get_translatable_grds(repo_root, grd_files,
5187 translation_expectations_path)
5188 except Exception as e:
5189 return [output_api.PresubmitNotifyResult(
5190 'Failed to get a list of translatable grd files. This happens when:\n'
5191 ' - One of the modified grd or grdp files cannot be parsed or\n'
5192 ' - %s is not updated.\n'
5193 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5194 return []
Ken Rockotc31f4832020-05-29 18:58:515195
5196
Saagar Sanghavifceeaae2020-08-12 16:40:365197def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515198 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095199 changed_mojoms = input_api.AffectedFiles(
5200 include_deletes=True,
5201 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515202 delta = []
5203 for mojom in changed_mojoms:
5204 old_contents = ''.join(mojom.OldContents()) or None
5205 new_contents = ''.join(mojom.NewContents()) or None
5206 delta.append({
5207 'filename': mojom.LocalPath(),
5208 'old': '\n'.join(mojom.OldContents()) or None,
5209 'new': '\n'.join(mojom.NewContents()) or None,
5210 })
5211
5212 process = input_api.subprocess.Popen(
5213 [input_api.python_executable,
5214 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5215 'public', 'tools', 'mojom',
5216 'check_stable_mojom_compatibility.py'),
5217 '--src-root', input_api.PresubmitLocalPath()],
5218 stdin=input_api.subprocess.PIPE,
5219 stdout=input_api.subprocess.PIPE,
5220 stderr=input_api.subprocess.PIPE,
5221 universal_newlines=True)
5222 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5223 if process.returncode:
5224 return [output_api.PresubmitError(
5225 'One or more [Stable] mojom definitions appears to have been changed '
5226 'in a way that is not backward-compatible.',
5227 long_text=error)]
5228 return []
Dominic Battre645d42342020-12-04 16:14:105229
5230def CheckDeprecationOfPreferences(input_api, output_api):
5231 """Removing a preference should come with a deprecation."""
5232
5233 def FilterFile(affected_file):
5234 """Accept only .cc files and the like."""
5235 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5236 files_to_skip = (_EXCLUDED_PATHS +
5237 _TEST_CODE_EXCLUDED_PATHS +
5238 input_api.DEFAULT_FILES_TO_SKIP)
5239 return input_api.FilterSourceFile(
5240 affected_file,
5241 files_to_check=file_inclusion_pattern,
5242 files_to_skip=files_to_skip)
5243
5244 def ModifiedLines(affected_file):
5245 """Returns a list of tuples (line number, line text) of added and removed
5246 lines.
5247
5248 Deleted lines share the same line number as the previous line.
5249
5250 This relies on the scm diff output describing each changed code section
5251 with a line of the form
5252
5253 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5254 """
5255 line_num = 0
5256 modified_lines = []
5257 for line in affected_file.GenerateScmDiff().splitlines():
5258 # Extract <new line num> of the patch fragment (see format above).
5259 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5260 if m:
5261 line_num = int(m.groups(1)[0])
5262 continue
5263 if ((line.startswith('+') and not line.startswith('++')) or
5264 (line.startswith('-') and not line.startswith('--'))):
5265 modified_lines.append((line_num, line))
5266
5267 if not line.startswith('-'):
5268 line_num += 1
5269 return modified_lines
5270
5271 def FindLineWith(lines, needle):
5272 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5273
5274 If 0 or >1 lines contain `needle`, -1 is returned.
5275 """
5276 matching_line_numbers = [
5277 # + 1 for 1-based counting of line numbers.
5278 i + 1 for i, line
5279 in enumerate(lines)
5280 if needle in line]
5281 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5282
5283 def ModifiedPrefMigration(affected_file):
5284 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5285 # Determine first and last lines of MigrateObsolete.*Pref functions.
5286 new_contents = affected_file.NewContents();
5287 range_1 = (
5288 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5289 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5290 range_2 = (
5291 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5292 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5293 if (-1 in range_1 + range_2):
5294 raise Exception(
5295 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5296
5297 # Check whether any of the modified lines are part of the
5298 # MigrateObsolete.*Pref functions.
5299 for line_nr, line in ModifiedLines(affected_file):
5300 if (range_1[0] <= line_nr <= range_1[1] or
5301 range_2[0] <= line_nr <= range_2[1]):
5302 return True
5303 return False
5304
5305 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5306 browser_prefs_file_pattern = input_api.re.compile(
5307 r'chrome/browser/prefs/browser_prefs.cc')
5308
5309 changes = input_api.AffectedFiles(include_deletes=True,
5310 file_filter=FilterFile)
5311 potential_problems = []
5312 for f in changes:
5313 for line in f.GenerateScmDiff().splitlines():
5314 # Check deleted lines for pref registrations.
5315 if (line.startswith('-') and not line.startswith('--') and
5316 register_pref_pattern.search(line)):
5317 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5318
5319 if browser_prefs_file_pattern.search(f.LocalPath()):
5320 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5321 # assume that they knew that they have to deprecate preferences and don't
5322 # warn.
5323 try:
5324 if ModifiedPrefMigration(f):
5325 return []
5326 except Exception as e:
5327 return [output_api.PresubmitError(str(e))]
5328
5329 if potential_problems:
5330 return [output_api.PresubmitPromptWarning(
5331 'Discovered possible removal of preference registrations.\n\n'
5332 'Please make sure to properly deprecate preferences by clearing their\n'
5333 'value for a couple of milestones before finally removing the code.\n'
5334 'Otherwise data may stay in the preferences files forever. See\n'
5335 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5336 'This may be a false positive warning (e.g. if you move preference\n'
5337 'registrations to a different place).\n',
5338 potential_problems
5339 )]
5340 return []