blob: 8f9116dd48a70454af16d59e6b8c63041be18a3c [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"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Sherman2112dd92020-07-22 23:08:5513 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
15 r"client_variations_parser.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)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0559 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4761 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0462 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0863 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0464 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4165 # EarlGrey app side code for tests.
66 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1767 # Views Examples code
68 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4469)
[email protected]ca8d1982009-02-19 16:33:1270
Daniel Bratell609102be2019-03-27 20:53:2171_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1572
[email protected]eea609a2011-11-18 13:10:1273_TEST_ONLY_WARNING = (
74 'You might be calling functions intended only for testing from\n'
75 'production code. It is OK to ignore this warning if you know what\n'
76 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0777 'not perfect. The commit queue will not block on this warning,\n'
78 'however the android-binary-size trybot will block if the method\n'
79 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1280
81
[email protected]cf9b78f2012-11-14 11:40:2882_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4083 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2184 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
85 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2886
Michael Thiessen44457642020-02-06 00:24:1587# Format: Sequence of tuples containing:
88# * Full import path.
89# * Sequence of strings to show when the pattern matches.
90# * Sequence of path or filename exceptions to this rule
91_BANNED_JAVA_IMPORTS = (
92 (
Colin Blundell170d78c82020-03-12 13:56:0493 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1594 (
95 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
96 ),
97 (
98 'net/android/javatests/src/org/chromium/net/'
99 'AndroidProxySelectorTest.java',
100 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04101 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15102 ),
103 ),
104)
wnwenbdc444e2016-05-25 13:44:15105
Daniel Bratell609102be2019-03-27 20:53:21106# Format: Sequence of tuples containing:
107# * String pattern or, if starting with a slash, a regular expression.
108# * Sequence of strings to show when the pattern matches.
109# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41110_BANNED_JAVA_FUNCTIONS = (
111 (
112 'StrictMode.allowThreadDiskReads()',
113 (
114 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
115 'directly.',
116 ),
117 False,
118 ),
119 (
120 'StrictMode.allowThreadDiskWrites()',
121 (
122 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
123 'directly.',
124 ),
125 False,
126 ),
127)
128
Daniel Bratell609102be2019-03-27 20:53:21129# Format: Sequence of tuples containing:
130# * String pattern or, if starting with a slash, a regular expression.
131# * Sequence of strings to show when the pattern matches.
132# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59133_BANNED_OBJC_FUNCTIONS = (
134 (
135 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59138 'prohibited. Please use CrTrackingArea instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 False,
142 ),
143 (
[email protected]eaae1972014-04-16 04:17:26144 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20145 (
146 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59147 'instead.',
148 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
149 ),
150 False,
151 ),
152 (
153 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20154 (
155 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59156 'Please use |convertPoint:(point) fromView:nil| instead.',
157 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
158 ),
159 True,
160 ),
161 (
162 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20163 (
164 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59165 'Please use |convertPoint:(point) toView:nil| instead.',
166 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
167 ),
168 True,
169 ),
170 (
171 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20172 (
173 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59174 'Please use |convertRect:(point) fromView:nil| instead.',
175 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
176 ),
177 True,
178 ),
179 (
180 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20181 (
182 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59183 'Please use |convertRect:(point) toView:nil| instead.',
184 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
185 ),
186 True,
187 ),
188 (
189 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20190 (
191 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59192 'Please use |convertSize:(point) fromView:nil| instead.',
193 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
194 ),
195 True,
196 ),
197 (
198 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20199 (
200 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59201 'Please use |convertSize:(point) toView:nil| instead.',
202 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
203 ),
204 True,
205 ),
jif65398702016-10-27 10:19:48206 (
207 r"/\s+UTF8String\s*]",
208 (
209 'The use of -[NSString UTF8String] is dangerous as it can return null',
210 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
211 'Please use |SysNSStringToUTF8| instead.',
212 ),
213 True,
214 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34215 (
216 r'__unsafe_unretained',
217 (
218 'The use of __unsafe_unretained is almost certainly wrong, unless',
219 'when interacting with NSFastEnumeration or NSInvocation.',
220 'Please use __weak in files build with ARC, nothing otherwise.',
221 ),
222 False,
223 ),
Avi Drissman7382afa02019-04-29 23:27:13224 (
225 'freeWhenDone:NO',
226 (
227 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
228 'Foundation types is prohibited.',
229 ),
230 True,
231 ),
[email protected]127f18ec2012-06-16 05:05:59232)
233
Daniel Bratell609102be2019-03-27 20:53:21234# Format: Sequence of tuples containing:
235# * String pattern or, if starting with a slash, a regular expression.
236# * Sequence of strings to show when the pattern matches.
237# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54238_BANNED_IOS_OBJC_FUNCTIONS = (
239 (
240 r'/\bTEST[(]',
241 (
242 'TEST() macro should not be used in Objective-C++ code as it does not ',
243 'drain the autorelease pool at the end of the test. Use TEST_F() ',
244 'macro instead with a fixture inheriting from PlatformTest (or a ',
245 'typedef).'
246 ),
247 True,
248 ),
249 (
250 r'/\btesting::Test\b',
251 (
252 'testing::Test should not be used in Objective-C++ code as it does ',
253 'not drain the autorelease pool at the end of the test. Use ',
254 'PlatformTest instead.'
255 ),
256 True,
257 ),
258)
259
Peter K. Lee6c03ccff2019-07-15 14:40:05260# Format: Sequence of tuples containing:
261# * String pattern or, if starting with a slash, a regular expression.
262# * Sequence of strings to show when the pattern matches.
263# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
264_BANNED_IOS_EGTEST_FUNCTIONS = (
265 (
266 r'/\bEXPECT_OCMOCK_VERIFY\b',
267 (
268 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
269 'it is meant for GTests. Use [mock verify] instead.'
270 ),
271 True,
272 ),
273)
274
danakj7a2b7082019-05-21 21:13:51275# Directories that contain deprecated Bind() or Callback types.
276# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36277# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51278# echo "-- $i"
danakj710b4c02019-11-28 16:08:45279# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51280# done
281#
282# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
283# when they have been converted to modern callback types (OnceCallback,
284# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
285# checks for them and prevent regressions.
286_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51287 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18288 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
289 '^chrome/browser/apps/guest_view/',
290 '^chrome/browser/apps/platform_apps/shortcut_manager.cc',
291 '^chrome/browser/browsing_data/',
292 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
293 '^chrome/browser/chromeos/',
294 '^chrome/browser/component_updater/',
295 '^chrome/browser/custom_handlers/protocol_handler_registry.cc',
296 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc',
297 '^chrome/browser/devtools/',
298 '^chrome/browser/download/',
299 '^chrome/browser/extensions/',
300 '^chrome/browser/external_protocol/external_protocol_handler.cc',
301 '^chrome/browser/history/',
302 '^chrome/browser/installable/installable_manager_browsertest.cc',
303 '^chrome/browser/lifetime/',
304 '^chrome/browser/media_galleries/',
305 '^chrome/browser/media/',
306 '^chrome/browser/metrics/',
307 '^chrome/browser/nacl_host/test/gdb_debug_stub_browsertest.cc',
308 '^chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl_unittest.cc',
309 '^chrome/browser/net/',
310 '^chrome/browser/notifications/',
311 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
312 '^chrome/browser/offline_pages/',
313 '^chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc',
314 '^chrome/browser/password_manager/',
315 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
316 '^chrome/browser/pdf/pdf_extension_test.cc',
317 '^chrome/browser/plugins/',
318 '^chrome/browser/policy/',
319 '^chrome/browser/portal/portal_browsertest.cc',
320 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
321 '^chrome/browser/prerender/',
322 '^chrome/browser/previews/',
323 '^chrome/browser/printing/printing_message_filter.cc',
324 '^chrome/browser/profiles/',
325 '^chrome/browser/profiling_host/profiling_process_host.cc',
326 '^chrome/browser/push_messaging/',
327 '^chrome/browser/recovery/recovery_install_global_error.cc',
328 '^chrome/browser/renderer_context_menu/',
329 '^chrome/browser/renderer_host/pepper/',
330 '^chrome/browser/resource_coordinator/',
331 '^chrome/browser/resources/chromeos/accessibility/',
332 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
333 '^chrome/browser/safe_browsing/',
334 '^chrome/browser/search_engines/',
335 '^chrome/browser/service_process/',
336 '^chrome/browser/signin/',
337 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
338 '^chrome/browser/ssl/',
339 '^chrome/browser/subresource_filter/',
340 '^chrome/browser/supervised_user/',
341 '^chrome/browser/sync_file_system/',
342 '^chrome/browser/sync/',
343 '^chrome/browser/themes/theme_service.cc',
344 '^chrome/browser/thumbnail/cc/',
345 '^chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc',
346 '^chrome/browser/translate/',
347 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18348 '^chrome/browser/web_applications/',
349 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51350 '^chrome/services/',
351 '^chrome/test/',
352 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51353 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51354 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51355 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51356 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51357 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51358 '^components/autofill/',
359 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51360 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51361 '^components/component_updater/',
362 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51363 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51364 '^components/nacl/',
365 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51366 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51367 '^components/password_manager/',
danakj7a2b7082019-05-21 21:13:51368 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51369 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51370 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51371 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51372 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51373 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51374 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20375 '^extensions/browser/',
376 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43377 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51378 '^ios/chrome/',
379 '^ios/components/',
380 '^ios/net/',
381 '^ios/web/',
382 '^ios/web_view/',
383 '^ipc/',
danakjc8576092019-11-26 19:01:36384 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51385 '^media/cast/',
386 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51387 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51388 '^media/gpu/',
389 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31390 '^net/http/',
391 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51392 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51393 '^remoting/host/',
danakj7a2b7082019-05-21 21:13:51394 '^services/',
danakj7a2b7082019-05-21 21:13:51395 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51396 '^tools/clang/base_bind_rewriters/', # Intentional.
397 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51398))
[email protected]127f18ec2012-06-16 05:05:59399
Daniel Bratell609102be2019-03-27 20:53:21400# Format: Sequence of tuples containing:
401# * String pattern or, if starting with a slash, a regular expression.
402# * Sequence of strings to show when the pattern matches.
403# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
404# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59405_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20406 (
Dave Tapuska98199b612019-07-10 13:30:44407 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53408 (
409 'New code should not use NULL. Use nullptr instead.',
410 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20411 False,
thomasandersone7caaa9b2017-03-29 19:22:53412 (),
413 ),
Peter Kasting94a56c42019-10-25 21:54:04414 (
415 r'/\busing namespace ',
416 (
417 'Using directives ("using namespace x") are banned by the Google Style',
418 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
419 'Explicitly qualify symbols or use using declarations ("using x::foo").',
420 ),
421 True,
422 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
423 ),
Antonio Gomes07300d02019-03-13 20:59:57424 # Make sure that gtest's FRIEND_TEST() macro is not used; the
425 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
426 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53427 (
[email protected]23e6cbc2012-06-16 18:51:20428 'FRIEND_TEST(',
429 (
[email protected]e3c945502012-06-26 20:01:49430 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20431 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
432 ),
433 False,
[email protected]7345da02012-11-27 14:31:49434 (),
[email protected]23e6cbc2012-06-16 18:51:20435 ),
436 (
Dave Tapuska98199b612019-07-10 13:30:44437 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53438 (
439 'Chrome clients wishing to select events on X windows should use',
440 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
441 'you are selecting events from the GPU process, or if you are using',
442 'an XDisplay other than gfx::GetXDisplay().',
443 ),
444 True,
445 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40446 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04447 r"^ui[\\/]gl[\\/].*\.cc$",
448 r"^media[\\/]gpu[\\/].*\.cc$",
449 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37450 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
451 ),
thomasanderson4b569052016-09-14 20:15:53452 ),
453 (
Tom Anderson74d064b2020-07-08 03:47:32454 r'/\WX?(((Width|Height)(MM)?OfScreen)|(Display(Width|Height)))\(',
455 (
456 'Use the corresponding fields in x11::Screen instead.',
457 ),
458 True,
459 (),
460 ),
461 (
Dave Tapuska98199b612019-07-10 13:30:44462 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20463 (
thomasanderson11aa41d2017-06-08 22:22:38464 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20465 ),
466 True,
467 (
Egor Paskoce145c42018-09-28 19:31:04468 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
469 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
470 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20471 ),
472 ),
473 (
tomhudsone2c14d552016-05-26 17:07:46474 'setMatrixClip',
475 (
476 'Overriding setMatrixClip() is prohibited; ',
477 'the base function is deprecated. ',
478 ),
479 True,
480 (),
481 ),
482 (
[email protected]52657f62013-05-20 05:30:31483 'SkRefPtr',
484 (
485 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22486 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31487 ),
488 True,
489 (),
490 ),
491 (
492 'SkAutoRef',
493 (
494 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22495 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31496 ),
497 True,
498 (),
499 ),
500 (
501 'SkAutoTUnref',
502 (
503 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22504 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31505 ),
506 True,
507 (),
508 ),
509 (
510 'SkAutoUnref',
511 (
512 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
513 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22514 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31515 ),
516 True,
517 (),
518 ),
[email protected]d89eec82013-12-03 14:10:59519 (
520 r'/HANDLE_EINTR\(.*close',
521 (
522 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
523 'descriptor will be closed, and it is incorrect to retry the close.',
524 'Either call close directly and ignore its return value, or wrap close',
525 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
526 ),
527 True,
528 (),
529 ),
530 (
531 r'/IGNORE_EINTR\((?!.*close)',
532 (
533 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
534 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
535 ),
536 True,
537 (
538 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04539 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
540 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59541 ),
542 ),
[email protected]ec5b3f02014-04-04 18:43:43543 (
544 r'/v8::Extension\(',
545 (
546 'Do not introduce new v8::Extensions into the code base, use',
547 'gin::Wrappable instead. See http://crbug.com/334679',
548 ),
549 True,
[email protected]f55c90ee62014-04-12 00:50:03550 (
Egor Paskoce145c42018-09-28 19:31:04551 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03552 ),
[email protected]ec5b3f02014-04-04 18:43:43553 ),
skyostilf9469f72015-04-20 10:38:52554 (
jame2d1a952016-04-02 00:27:10555 '#pragma comment(lib,',
556 (
557 'Specify libraries to link with in build files and not in the source.',
558 ),
559 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41560 (
tzik3f295992018-12-04 20:32:23561 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04562 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41563 ),
jame2d1a952016-04-02 00:27:10564 ),
fdorayc4ac18d2017-05-01 21:39:59565 (
Gabriel Charette7cc6c432018-04-25 20:52:02566 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59567 (
568 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
569 ),
570 False,
571 (),
572 ),
573 (
Gabriel Charette7cc6c432018-04-25 20:52:02574 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59575 (
576 'Consider using THREAD_CHECKER macros instead of the class directly.',
577 ),
578 False,
579 (),
580 ),
dbeamb6f4fde2017-06-15 04:03:06581 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06582 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
583 (
584 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
585 'deprecated (http://crbug.com/634507). Please avoid converting away',
586 'from the Time types in Chromium code, especially if any math is',
587 'being done on time values. For interfacing with platform/library',
588 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
589 'type converter methods instead. For faking TimeXXX values (for unit',
590 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
591 'other use cases, please contact base/time/OWNERS.',
592 ),
593 False,
594 (),
595 ),
596 (
dbeamb6f4fde2017-06-15 04:03:06597 'CallJavascriptFunctionUnsafe',
598 (
599 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
600 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
601 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
602 ),
603 False,
604 (
Egor Paskoce145c42018-09-28 19:31:04605 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
606 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
607 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06608 ),
609 ),
dskiba1474c2bfd62017-07-20 02:19:24610 (
611 'leveldb::DB::Open',
612 (
613 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
614 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
615 "Chrome's tracing, making their memory usage visible.",
616 ),
617 True,
618 (
619 r'^third_party/leveldatabase/.*\.(cc|h)$',
620 ),
Gabriel Charette0592c3a2017-07-26 12:02:04621 ),
622 (
Chris Mumfordc38afb62017-10-09 17:55:08623 'leveldb::NewMemEnv',
624 (
625 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58626 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
627 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08628 ),
629 True,
630 (
631 r'^third_party/leveldatabase/.*\.(cc|h)$',
632 ),
633 ),
634 (
Gabriel Charetted9839bc2017-07-29 14:17:47635 'RunLoop::QuitCurrent',
636 (
Robert Liao64b7ab22017-08-04 23:03:43637 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
638 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47639 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41640 False,
Gabriel Charetted9839bc2017-07-29 14:17:47641 (),
Gabriel Charettea44975052017-08-21 23:14:04642 ),
643 (
644 'base::ScopedMockTimeMessageLoopTaskRunner',
645 (
Gabriel Charette87cc1af2018-04-25 20:52:51646 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11647 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51648 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
649 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
650 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04651 ),
Gabriel Charette87cc1af2018-04-25 20:52:51652 False,
Gabriel Charettea44975052017-08-21 23:14:04653 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57654 ),
655 (
Dave Tapuska98199b612019-07-10 13:30:44656 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57657 (
658 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02659 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57660 ),
661 True,
662 (),
Francois Doray43670e32017-09-27 12:40:38663 ),
664 (
Peter Kasting991618a62019-06-17 22:00:09665 r'/\bstd::stoi\b',
666 (
667 'std::stoi uses exceptions to communicate results. ',
668 'Use base::StringToInt() instead.',
669 ),
670 True,
671 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
672 ),
673 (
674 r'/\bstd::stol\b',
675 (
676 'std::stol uses exceptions to communicate results. ',
677 'Use base::StringToInt() instead.',
678 ),
679 True,
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::stoul\b',
684 (
685 'std::stoul uses exceptions to communicate results. ',
686 'Use base::StringToUint() instead.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
690 ),
691 (
692 r'/\bstd::stoll\b',
693 (
694 'std::stoll uses exceptions to communicate results. ',
695 'Use base::StringToInt64() instead.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
699 ),
700 (
701 r'/\bstd::stoull\b',
702 (
703 'std::stoull uses exceptions to communicate results. ',
704 'Use base::StringToUint64() instead.',
705 ),
706 True,
707 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
708 ),
709 (
710 r'/\bstd::stof\b',
711 (
712 'std::stof uses exceptions to communicate results. ',
713 'For locale-independent values, e.g. reading numbers from disk',
714 'profiles, use base::StringToDouble().',
715 'For user-visible values, parse using ICU.',
716 ),
717 True,
718 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
719 ),
720 (
721 r'/\bstd::stod\b',
722 (
723 'std::stod uses exceptions to communicate results. ',
724 'For locale-independent values, e.g. reading numbers from disk',
725 'profiles, use base::StringToDouble().',
726 'For user-visible values, parse using ICU.',
727 ),
728 True,
729 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
730 ),
731 (
732 r'/\bstd::stold\b',
733 (
734 'std::stold uses exceptions to communicate results. ',
735 'For locale-independent values, e.g. reading numbers from disk',
736 'profiles, use base::StringToDouble().',
737 'For user-visible values, parse using ICU.',
738 ),
739 True,
740 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
741 ),
742 (
Daniel Bratell69334cc2019-03-26 11:07:45743 r'/\bstd::to_string\b',
744 (
745 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09746 'For locale-independent strings, e.g. writing numbers to disk',
747 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45748 'For user-visible strings, use base::FormatNumber() and',
749 'the related functions in base/i18n/number_formatting.h.',
750 ),
Peter Kasting991618a62019-06-17 22:00:09751 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21752 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45753 ),
754 (
755 r'/\bstd::shared_ptr\b',
756 (
757 'std::shared_ptr should not be used. Use scoped_refptr instead.',
758 ),
759 True,
Alex Chau9eb03cdd52020-07-13 21:04:57760 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
761 'array_buffer_contents\.(cc|h)',
762 # Needed for interop with third-party library
763 'chrome/services/sharing/nearby/',
764 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21765 ),
766 (
Peter Kasting991618a62019-06-17 22:00:09767 r'/\bstd::weak_ptr\b',
768 (
769 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
770 ),
771 True,
772 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
773 ),
774 (
Daniel Bratell609102be2019-03-27 20:53:21775 r'/\blong long\b',
776 (
777 'long long is banned. Use stdint.h if you need a 64 bit number.',
778 ),
779 False, # Only a warning since it is already used.
780 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
781 ),
782 (
783 r'/\bstd::bind\b',
784 (
785 'std::bind is banned because of lifetime risks.',
786 'Use base::BindOnce or base::BindRepeating instead.',
787 ),
788 True,
789 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
790 ),
791 (
792 r'/\b#include <chrono>\b',
793 (
794 '<chrono> overlaps with Time APIs in base. Keep using',
795 'base classes.',
796 ),
797 True,
798 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
799 ),
800 (
801 r'/\b#include <exception>\b',
802 (
803 'Exceptions are banned and disabled in Chromium.',
804 ),
805 True,
806 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
807 ),
808 (
809 r'/\bstd::function\b',
810 (
811 'std::function is banned. Instead use base::Callback which directly',
812 'supports Chromium\'s weak pointers, ref counting and more.',
813 ),
Peter Kasting991618a62019-06-17 22:00:09814 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21815 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
816 ),
817 (
818 r'/\b#include <random>\b',
819 (
820 'Do not use any random number engines from <random>. Instead',
821 'use base::RandomBitGenerator.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
825 ),
826 (
827 r'/\bstd::ratio\b',
828 (
829 'std::ratio is banned by the Google Style Guide.',
830 ),
831 True,
832 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45833 ),
834 (
Francois Doray43670e32017-09-27 12:40:38835 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
836 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
837 (
838 'Use the new API in base/threading/thread_restrictions.h.',
839 ),
Gabriel Charette04b138f2018-08-06 00:03:22840 False,
Francois Doray43670e32017-09-27 12:40:38841 (),
842 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38843 (
danakj7a2b7082019-05-21 21:13:51844 r'/\bbase::Bind\(',
845 (
846 'Please use base::Bind{Once,Repeating} instead',
847 'of base::Bind. (crbug.com/714018)',
848 ),
849 False,
Erik Staaba737d7602019-11-25 18:41:07850 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51851 ),
852 (
853 r'/\bbase::Callback[<:]',
854 (
855 'Please use base::{Once,Repeating}Callback instead',
856 'of base::Callback. (crbug.com/714018)',
857 ),
858 False,
Erik Staaba737d7602019-11-25 18:41:07859 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51860 ),
861 (
862 r'/\bbase::Closure\b',
863 (
864 'Please use base::{Once,Repeating}Closure instead',
865 'of base::Closure. (crbug.com/714018)',
866 ),
867 False,
Erik Staaba737d7602019-11-25 18:41:07868 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51869 ),
870 (
Michael Giuffrida7f93d6922019-04-19 14:39:58871 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunMessageLoop is deprecated, use RunLoop instead.',
874 ),
875 False,
876 (),
877 ),
878 (
Dave Tapuska98199b612019-07-10 13:30:44879 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19880 (
881 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
882 ),
883 False,
884 (),
885 ),
886 (
Dave Tapuska98199b612019-07-10 13:30:44887 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19888 (
889 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
890 "if you're convinced you need this.",
891 ),
892 False,
893 (),
894 ),
895 (
Dave Tapuska98199b612019-07-10 13:30:44896 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19897 (
898 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04899 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19900 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
901 'async events instead of flushing threads.',
902 ),
903 False,
904 (),
905 ),
906 (
907 r'MessageLoopRunner',
908 (
909 'MessageLoopRunner is deprecated, use RunLoop instead.',
910 ),
911 False,
912 (),
913 ),
914 (
Dave Tapuska98199b612019-07-10 13:30:44915 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19916 (
917 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
918 "gab@ if you found a use case where this is the only solution.",
919 ),
920 False,
921 (),
922 ),
923 (
Victor Costane48a2e82019-03-15 22:02:34924 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16925 (
Victor Costane48a2e82019-03-15 22:02:34926 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16927 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
928 ),
929 True,
930 (
931 r'^sql/initialization\.(cc|h)$',
932 r'^third_party/sqlite/.*\.(c|cc|h)$',
933 ),
934 ),
Matt Menke7f520a82018-03-28 21:38:37935 (
Dave Tapuska98199b612019-07-10 13:30:44936 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47937 (
938 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
939 'base::RandomShuffle instead.'
940 ),
941 True,
942 (),
943 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24944 (
945 'ios/web/public/test/http_server',
946 (
947 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
948 ),
949 False,
950 (),
951 ),
Robert Liao764c9492019-01-24 18:46:28952 (
953 'GetAddressOf',
954 (
955 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53956 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
957 'operator& is generally recommended. So always use operator& instead. '
958 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28959 ),
960 True,
961 (),
962 ),
Antonio Gomes07300d02019-03-13 20:59:57963 (
964 'DEFINE_TYPE_CASTS',
965 (
966 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
967 '//third_party/blink/renderer/platform/casting.h.'
968 ),
969 True,
970 (
971 r'^third_party/blink/renderer/.*\.(cc|h)$',
972 ),
973 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38974 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45975 r'/\bIsHTML.+Element\(\b',
976 (
977 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
978 ' helpers IsA<HTMLXXXXElement> from ',
979 '//third_party/blink/renderer/platform/casting.h.'
980 ),
981 False,
982 (
983 r'^third_party/blink/renderer/.*\.(cc|h)$',
984 ),
985 ),
986 (
987 r'/\bToHTML.+Element(|OrNull)\(\b',
988 (
989 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
990 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
991 'and DynamicTo<HTMLXXXXElement> from ',
992 '//third_party/blink/renderer/platform/casting.h.'
993 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
994 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
995 ),
996 False,
997 (
998 r'^third_party/blink/renderer/.*\.(cc|h)$',
999 ),
1000 ),
1001 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371002 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381003 (
1004 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1005 ),
1006 True,
1007 (),
1008 ),
Ben Lewisa9514602019-04-29 17:53:051009 (
1010 'SHFileOperation',
1011 (
1012 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1013 'complex functions to achieve the same goals. Use IFileOperation for ',
1014 'any esoteric actions instead.'
1015 ),
1016 True,
1017 (),
1018 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181019 (
Cliff Smolinsky81951642019-04-30 21:39:511020 'StringFromGUID2',
1021 (
1022 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241023 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511024 ),
1025 True,
1026 (
1027 r'/base/win/win_util_unittest.cc'
1028 ),
1029 ),
1030 (
1031 'StringFromCLSID',
1032 (
1033 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241034 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511035 ),
1036 True,
1037 (
1038 r'/base/win/win_util_unittest.cc'
1039 ),
1040 ),
1041 (
Avi Drissman7382afa02019-04-29 23:27:131042 'kCFAllocatorNull',
1043 (
1044 'The use of kCFAllocatorNull with the NoCopy creation of ',
1045 'CoreFoundation types is prohibited.',
1046 ),
1047 True,
1048 (),
1049 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291050 (
1051 'mojo::ConvertTo',
1052 (
1053 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1054 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1055 'StringTraits if you would like to convert between custom types and',
1056 'the wire format of mojom types.'
1057 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221058 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291059 (
Wezf89dec092019-09-11 19:38:331060 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1061 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291062 r'^third_party/blink/.*\.(cc|h)$',
1063 r'^content/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Robert Liao1d78df52019-11-11 20:02:011066 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161067 'GetInterfaceProvider',
1068 (
1069 'InterfaceProvider is deprecated.',
1070 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1071 'or Platform::GetBrowserInterfaceBroker.'
1072 ),
1073 False,
1074 (),
1075 ),
1076 (
Robert Liao1d78df52019-11-11 20:02:011077 'CComPtr',
1078 (
1079 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1080 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1081 'details.'
1082 ),
1083 False,
1084 (),
1085 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201086 (
1087 r'/\b(IFACE|STD)METHOD_?\(',
1088 (
1089 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1090 'Instead, always use IFACEMETHODIMP in the declaration.'
1091 ),
1092 False,
1093 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1094 ),
Allen Bauer53b43fb12020-03-12 17:21:471095 (
1096 'set_owned_by_client',
1097 (
1098 'set_owned_by_client is deprecated.',
1099 'views::View already owns the child views by default. This introduces ',
1100 'a competing ownership model which makes the code difficult to reason ',
1101 'about. See http://crbug.com/1044687 for more details.'
1102 ),
1103 False,
1104 (),
1105 ),
Eric Secklerbe6f48d2020-05-06 18:09:121106 (
1107 r'/\bTRACE_EVENT_ASYNC_',
1108 (
1109 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1110 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1111 ),
1112 False,
1113 (
1114 r'^base/trace_event/.*',
1115 r'^base/tracing/.*',
1116 ),
1117 ),
[email protected]127f18ec2012-06-16 05:05:591118)
1119
Mario Sanchez Prada2472cab2019-09-18 10:58:311120# Format: Sequence of tuples containing:
1121# * String pattern or, if starting with a slash, a regular expression.
1122# * Sequence of strings to show when the pattern matches.
1123_DEPRECATED_MOJO_TYPES = (
1124 (
1125 r'/\bmojo::AssociatedBinding\b',
1126 (
1127 'mojo::AssociatedBinding<Interface> is deprecated.',
1128 'Use mojo::AssociatedReceiver<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::AssociatedBindingSet\b',
1133 (
1134 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1135 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::AssociatedInterfacePtr\b',
1140 (
1141 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1142 'Use mojo::AssociatedRemote<Interface> instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1147 (
1148 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1149 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1150 ),
1151 ),
1152 (
1153 r'/\bmojo::AssociatedInterfaceRequest\b',
1154 (
1155 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1156 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1157 ),
1158 ),
1159 (
1160 r'/\bmojo::Binding\b',
1161 (
1162 'mojo::Binding<Interface> is deprecated.',
1163 'Use mojo::Receiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::BindingSet\b',
1168 (
1169 'mojo::BindingSet<Interface> is deprecated.',
1170 'Use mojo::ReceiverSet<Interface> instead.',
1171 ),
1172 ),
1173 (
1174 r'/\bmojo::InterfacePtr\b',
1175 (
1176 'mojo::InterfacePtr<Interface> is deprecated.',
1177 'Use mojo::Remote<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::InterfacePtrInfo\b',
1182 (
1183 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1184 'Use mojo::PendingRemote<Interface> instead.',
1185 ),
1186 ),
1187 (
1188 r'/\bmojo::InterfaceRequest\b',
1189 (
1190 'mojo::InterfaceRequest<Interface> is deprecated.',
1191 'Use mojo::PendingReceiver<Interface> instead.',
1192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeRequest\b',
1196 (
1197 'mojo::MakeRequest is deprecated.',
1198 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1203 (
1204 'mojo::MakeRequest is deprecated.',
1205 'Use mojo::AssociatedRemote::'
1206 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongBinding\b',
1211 (
1212 'mojo::MakeStrongBinding is deprecated.',
1213 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1214 'mojo::MakeSelfOwnedReceiver() instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::MakeStrongAssociatedBinding\b',
1219 (
1220 'mojo::MakeStrongAssociatedBinding is deprecated.',
1221 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1222 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1223 ),
1224 ),
1225 (
Gyuyoung Kim4952ba62020-07-07 07:33:441226 r'/\bmojo::StrongAssociatedBinding\b',
1227 (
1228 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1229 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1230 ),
1231 ),
1232 (
1233 r'/\bmojo::StrongBinding\b',
1234 (
1235 'mojo::StrongBinding<Interface> is deprecated.',
1236 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1237 ),
1238 ),
1239 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311240 r'/\bmojo::StrongAssociatedBindingSet\b',
1241 (
1242 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1243 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1244 ),
1245 ),
1246 (
1247 r'/\bmojo::StrongBindingSet\b',
1248 (
1249 'mojo::StrongBindingSet<Interface> is deprecated.',
1250 'Use mojo::UniqueReceiverSet<Interface> instead.',
1251 ),
1252 ),
1253)
wnwenbdc444e2016-05-25 13:44:151254
mlamouria82272622014-09-16 18:45:041255_IPC_ENUM_TRAITS_DEPRECATED = (
1256 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501257 'See http://www.chromium.org/Home/chromium-security/education/'
1258 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041259
Stephen Martinis97a394142018-06-07 23:06:051260_LONG_PATH_ERROR = (
1261 'Some files included in this CL have file names that are too long (> 200'
1262 ' characters). If committed, these files will cause issues on Windows. See'
1263 ' https://crbug.com/612667 for more details.'
1264)
1265
Shenghua Zhangbfaa38b82017-11-16 21:58:021266_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041267 r".*[\\/]BuildHooksAndroidImpl\.java",
1268 r".*[\\/]LicenseContentProvider\.java",
1269 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281270 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021271]
[email protected]127f18ec2012-06-16 05:05:591272
Mohamed Heikald048240a2019-11-12 16:57:371273# List of image extensions that are used as resources in chromium.
1274_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1275
Sean Kau46e29bc2017-08-28 16:31:161276# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401277_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041278 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401279 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041280 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1281 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041282 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431283 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161284]
1285
1286
[email protected]b00342e7f2013-03-26 16:21:541287_VALID_OS_MACROS = (
1288 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081289 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541290 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121291 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541292 'OS_BSD',
1293 'OS_CAT', # For testing.
1294 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041295 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541296 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371297 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541298 'OS_IOS',
1299 'OS_LINUX',
1300 'OS_MACOSX',
1301 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211302 'OS_NACL_NONSFI',
1303 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121304 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541305 'OS_OPENBSD',
1306 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371307 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541308 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541309 'OS_WIN',
1310)
1311
1312
Andrew Grieveb773bad2020-06-05 18:00:381313# These are not checked on the public chromium-presubmit trybot.
1314# Add files here that rely on .py files that exists only for target_os="android"
1315# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401316_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391317 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381318 'build/android/devil_chromium.pydeps',
1319 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1320 'build/android/gyp/jinja_template.pydeps',
1321 'build/android/resource_sizes.pydeps',
1322 'build/android/test_runner.pydeps',
1323 'build/android/test_wrapper/logdog_wrapper.pydeps',
1324 'chrome/android/features/create_stripped_java_factory.pydeps',
1325 'testing/scripts/run_android_wpt.pydeps',
1326 'third_party/android_platform/development/scripts/stack.pydeps',
1327]
1328
1329
1330_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361331 'base/android/jni_generator/jni_generator.pydeps',
1332 'base/android/jni_generator/jni_registration_generator.pydeps',
1333 'build/android/gyp/aar.pydeps',
1334 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271335 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381337 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111339 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111343 'build/android/gyp/create_app_bundle_apks.pydeps',
1344 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361345 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121346 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221347 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001348 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591350 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421352 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/filter_zip.pydeps',
1355 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361356 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581358 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261360 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011361 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/gyp/lint.pydeps',
1363 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361364 'build/android/gyp/merge_manifest.pydeps',
1365 'build/android/gyp/prepare_resources.pydeps',
1366 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461367 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241368 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361369 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461370 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561371 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361372 'build/android/incremental_install/generate_android_manifest.pydeps',
1373 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271375 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1376 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001377 'components/cronet/tools/generate_javadoc.pydeps',
1378 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381379 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001380 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381381 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421382 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1383 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131384 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191385 ('third_party/blink/renderer/bindings/scripts/'
1386 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061387 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221388 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401389]
1390
wnwenbdc444e2016-05-25 13:44:151391
agrievef32bcc72016-04-04 14:57:401392_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1393
1394
Eric Boren6fd2b932018-01-25 15:05:081395# Bypass the AUTHORS check for these accounts.
1396_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591397 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451398 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591399 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521400 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1401 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041402 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271403 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041404 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301405 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081406
1407
Daniel Bratell65b033262019-04-23 08:17:061408def _IsCPlusPlusFile(input_api, file_path):
1409 """Returns True if this file contains C++-like code (and not Python,
1410 Go, Java, MarkDown, ...)"""
1411
1412 ext = input_api.os_path.splitext(file_path)[1]
1413 # This list is compatible with CppChecker.IsCppFile but we should
1414 # consider adding ".c" to it. If we do that we can use this function
1415 # at more places in the code.
1416 return ext in (
1417 '.h',
1418 '.cc',
1419 '.cpp',
1420 '.m',
1421 '.mm',
1422 )
1423
1424def _IsCPlusPlusHeaderFile(input_api, file_path):
1425 return input_api.os_path.splitext(file_path)[1] == ".h"
1426
1427
1428def _IsJavaFile(input_api, file_path):
1429 return input_api.os_path.splitext(file_path)[1] == ".java"
1430
1431
1432def _IsProtoFile(input_api, file_path):
1433 return input_api.os_path.splitext(file_path)[1] == ".proto"
1434
[email protected]55459852011-08-10 15:17:191435def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1436 """Attempts to prevent use of functions intended only for testing in
1437 non-testing code. For now this is just a best-effort implementation
1438 that ignores header files and may have some false positives. A
1439 better implementation would probably need a proper C++ parser.
1440 """
1441 # We only scan .cc files and the like, as the declaration of
1442 # for-testing functions in header files are hard to distinguish from
1443 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491444 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191445
jochenc0d4808c2015-07-27 09:25:421446 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191447 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091448 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191449 exclusion_pattern = input_api.re.compile(
1450 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1451 base_function_pattern, base_function_pattern))
1452
1453 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441454 files_to_skip = (_EXCLUDED_PATHS +
1455 _TEST_CODE_EXCLUDED_PATHS +
1456 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191457 return input_api.FilterSourceFile(
1458 affected_file,
James Cook24a504192020-07-23 00:08:441459 files_to_check=file_inclusion_pattern,
1460 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191461
1462 problems = []
1463 for f in input_api.AffectedSourceFiles(FilterFile):
1464 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241465 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031466 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461467 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031468 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191469 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031470 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191471
1472 if problems:
[email protected]f7051d52013-04-02 18:31:421473 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031474 else:
1475 return []
[email protected]55459852011-08-10 15:17:191476
1477
Vaclav Brozek7dbc28c2018-03-27 08:35:231478def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1479 """This is a simplified version of
1480 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1481 """
1482 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1483 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1484 name_pattern = r'ForTest(s|ing)?'
1485 # Describes an occurrence of "ForTest*" inside a // comment.
1486 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1487 # Catch calls.
1488 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1489 # Ignore definitions. (Comments are ignored separately.)
1490 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1491
1492 problems = []
1493 sources = lambda x: input_api.FilterSourceFile(
1494 x,
James Cook24a504192020-07-23 00:08:441495 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1496 + input_api.DEFAULT_FILES_TO_SKIP),
1497 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231498 )
1499 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1500 local_path = f.LocalPath()
1501 is_inside_javadoc = False
1502 for line_number, line in f.ChangedContents():
1503 if is_inside_javadoc and javadoc_end_re.search(line):
1504 is_inside_javadoc = False
1505 if not is_inside_javadoc and javadoc_start_re.search(line):
1506 is_inside_javadoc = True
1507 if is_inside_javadoc:
1508 continue
1509 if (inclusion_re.search(line) and
1510 not comment_re.search(line) and
1511 not exclusion_re.search(line)):
1512 problems.append(
1513 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1514
1515 if problems:
1516 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1517 else:
1518 return []
1519
1520
[email protected]10689ca2011-09-02 02:31:541521def _CheckNoIOStreamInHeaders(input_api, output_api):
1522 """Checks to make sure no .h files include <iostream>."""
1523 files = []
1524 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1525 input_api.re.MULTILINE)
1526 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1527 if not f.LocalPath().endswith('.h'):
1528 continue
1529 contents = input_api.ReadFile(f)
1530 if pattern.search(contents):
1531 files.append(f)
1532
1533 if len(files):
yolandyandaabc6d2016-04-18 18:29:391534 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061535 'Do not #include <iostream> in header files, since it inserts static '
1536 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541537 '#include <ostream>. See http://crbug.com/94794',
1538 files) ]
1539 return []
1540
Danil Chapovalov3518f362018-08-11 16:13:431541def _CheckNoStrCatRedefines(input_api, output_api):
1542 """Checks no windows headers with StrCat redefined are included directly."""
1543 files = []
1544 pattern_deny = input_api.re.compile(
1545 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1546 input_api.re.MULTILINE)
1547 pattern_allow = input_api.re.compile(
1548 r'^#include\s"base/win/windows_defines.inc"',
1549 input_api.re.MULTILINE)
1550 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1551 contents = input_api.ReadFile(f)
1552 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1553 files.append(f.LocalPath())
1554
1555 if len(files):
1556 return [output_api.PresubmitError(
1557 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1558 'directly since they pollute code with StrCat macro. Instead, '
1559 'include matching header from base/win. See http://crbug.com/856536',
1560 files) ]
1561 return []
1562
[email protected]10689ca2011-09-02 02:31:541563
[email protected]72df4e782012-06-21 16:28:181564def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521565 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181566 problems = []
1567 for f in input_api.AffectedFiles():
1568 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1569 continue
1570
1571 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041572 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181573 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1574
1575 if not problems:
1576 return []
1577 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1578 '\n'.join(problems))]
1579
Dominic Battre033531052018-09-24 15:45:341580def _CheckNoDISABLETypoInTests(input_api, output_api):
1581 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1582
1583 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1584 instead of DISABLED_. To filter false positives, reports are only generated
1585 if a corresponding MAYBE_ line exists.
1586 """
1587 problems = []
1588
1589 # The following two patterns are looked for in tandem - is a test labeled
1590 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1591 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1592 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1593
1594 # This is for the case that a test is disabled on all platforms.
1595 full_disable_pattern = input_api.re.compile(
1596 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1597 input_api.re.MULTILINE)
1598
Katie Df13948e2018-09-25 07:33:441599 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341600 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1601 continue
1602
1603 # Search for MABYE_, DISABLE_ pairs.
1604 disable_lines = {} # Maps of test name to line number.
1605 maybe_lines = {}
1606 for line_num, line in f.ChangedContents():
1607 disable_match = disable_pattern.search(line)
1608 if disable_match:
1609 disable_lines[disable_match.group(1)] = line_num
1610 maybe_match = maybe_pattern.search(line)
1611 if maybe_match:
1612 maybe_lines[maybe_match.group(1)] = line_num
1613
1614 # Search for DISABLE_ occurrences within a TEST() macro.
1615 disable_tests = set(disable_lines.keys())
1616 maybe_tests = set(maybe_lines.keys())
1617 for test in disable_tests.intersection(maybe_tests):
1618 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1619
1620 contents = input_api.ReadFile(f)
1621 full_disable_match = full_disable_pattern.search(contents)
1622 if full_disable_match:
1623 problems.append(' %s' % f.LocalPath())
1624
1625 if not problems:
1626 return []
1627 return [
1628 output_api.PresubmitPromptWarning(
1629 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1630 '\n'.join(problems))
1631 ]
1632
[email protected]72df4e782012-06-21 16:28:181633
danakj61c1aa22015-10-26 19:55:521634def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571635 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521636 errors = []
Hans Wennborg944479f2020-06-25 21:39:251637 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521638 input_api.re.MULTILINE)
1639 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1640 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1641 continue
1642 for lnum, line in f.ChangedContents():
1643 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171644 errors.append(output_api.PresubmitError(
1645 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571646 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171647 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521648 return errors
1649
1650
Makoto Shimazu3ad422cd2019-05-08 02:35:141651def _FindHistogramNameInChunk(histogram_name, chunk):
1652 """Tries to find a histogram name or prefix in a line.
1653
1654 Returns the existence of the histogram name, or None if it needs more chunk
1655 to determine."""
mcasasb7440c282015-02-04 14:52:191656 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1657 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141658 if '<affected-histogram' in chunk:
1659 # If the tag is not completed, needs more chunk to get the name.
1660 if not '>' in chunk:
1661 return None
1662 if not 'name="' in chunk:
1663 return False
1664 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1665 # expect the only attribute is the name.
1666 histogram_prefix = chunk.split('"')[1]
1667 return histogram_prefix in histogram_name
1668 # Typically the whole histogram name should in the line.
1669 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191670
1671
1672def _CheckUmaHistogramChanges(input_api, output_api):
1673 """Check that UMA histogram names in touched lines can still be found in other
1674 lines of the patch or in histograms.xml. Note that this check would not catch
1675 the reverse: changes in histograms.xml not matched in the code itself."""
1676 touched_histograms = []
1677 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471678 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1679 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1680 name_pattern = r'"(.*?)"'
1681 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1682 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1683 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1684 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1685 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171686 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191687 for f in input_api.AffectedFiles():
1688 # If histograms.xml itself is modified, keep the modified lines for later.
1689 if f.LocalPath().endswith(('histograms.xml')):
1690 histograms_xml_modifications = f.ChangedContents()
1691 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471692 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1693 single_line_re = single_line_c_re
1694 split_line_prefix_re = split_line_c_prefix_re
1695 elif f.LocalPath().endswith(('java')):
1696 single_line_re = single_line_java_re
1697 split_line_prefix_re = split_line_java_prefix_re
1698 else:
mcasasb7440c282015-02-04 14:52:191699 continue
1700 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171701 if last_line_matched_prefix:
1702 suffix_found = split_line_suffix_re.search(line)
1703 if suffix_found :
1704 touched_histograms.append([suffix_found.group(1), f, line_num])
1705 last_line_matched_prefix = False
1706 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061707 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191708 if found:
1709 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171710 continue
1711 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191712
1713 # Search for the touched histogram names in the local modifications to
1714 # histograms.xml, and, if not found, on the base histograms.xml file.
1715 unmatched_histograms = []
1716 for histogram_info in touched_histograms:
1717 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141718 chunk = ''
mcasasb7440c282015-02-04 14:52:191719 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141720 chunk += line
1721 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1722 if histogram_name_found is None:
1723 continue
1724 chunk = ''
mcasasb7440c282015-02-04 14:52:191725 if histogram_name_found:
1726 break
1727 if not histogram_name_found:
1728 unmatched_histograms.append(histogram_info)
1729
eromanb90c82e7e32015-04-01 15:13:491730 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191731 problems = []
1732 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491733 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191734 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451735 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191736 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141737 chunk = ''
mcasasb7440c282015-02-04 14:52:191738 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141739 chunk += line
1740 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1741 chunk)
1742 if histogram_name_found is None:
1743 continue
1744 chunk = ''
mcasasb7440c282015-02-04 14:52:191745 if histogram_name_found:
1746 break
1747 if not histogram_name_found:
1748 problems.append(' [%s:%d] %s' %
1749 (f.LocalPath(), line_num, histogram_name))
1750
1751 if not problems:
1752 return []
1753 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1754 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491755 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191756
wnwenbdc444e2016-05-25 13:44:151757
yolandyandaabc6d2016-04-18 18:29:391758def _CheckFlakyTestUsage(input_api, output_api):
1759 """Check that FlakyTest annotation is our own instead of the android one"""
1760 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1761 files = []
1762 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1763 if f.LocalPath().endswith('Test.java'):
1764 if pattern.search(input_api.ReadFile(f)):
1765 files.append(f)
1766 if len(files):
1767 return [output_api.PresubmitError(
1768 'Use org.chromium.base.test.util.FlakyTest instead of '
1769 'android.test.FlakyTest',
1770 files)]
1771 return []
mcasasb7440c282015-02-04 14:52:191772
wnwenbdc444e2016-05-25 13:44:151773
[email protected]8ea5d4b2011-09-13 21:49:221774def _CheckNoNewWStrings(input_api, output_api):
1775 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271776 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221777 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201778 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571779 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341780 '/win/' in f.LocalPath() or
1781 'chrome_elf' in f.LocalPath() or
1782 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201783 continue
[email protected]8ea5d4b2011-09-13 21:49:221784
[email protected]a11dbe9b2012-08-07 01:32:581785 allowWString = False
[email protected]b5c24292011-11-28 14:38:201786 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581787 if 'presubmit: allow wstring' in line:
1788 allowWString = True
1789 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271790 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581791 allowWString = False
1792 else:
1793 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221794
[email protected]55463aa62011-10-12 00:48:271795 if not problems:
1796 return []
1797 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581798 ' If you are calling a cross-platform API that accepts a wstring, '
1799 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271800 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221801
1802
[email protected]2a8ac9c2011-10-19 17:20:441803def _CheckNoDEPSGIT(input_api, output_api):
1804 """Make sure .DEPS.git is never modified manually."""
1805 if any(f.LocalPath().endswith('.DEPS.git') for f in
1806 input_api.AffectedFiles()):
1807 return [output_api.PresubmitError(
1808 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1809 'automated system based on what\'s in DEPS and your changes will be\n'
1810 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501811 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1812 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441813 'for more information')]
1814 return []
1815
1816
tandriief664692014-09-23 14:51:471817def _CheckValidHostsInDEPS(input_api, output_api):
1818 """Checks that DEPS file deps are from allowed_hosts."""
1819 # Run only if DEPS file has been modified to annoy fewer bystanders.
1820 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1821 return []
1822 # Outsource work to gclient verify
1823 try:
John Budorickf20c0042019-04-25 23:23:401824 gclient_path = input_api.os_path.join(
1825 input_api.PresubmitLocalPath(),
1826 'third_party', 'depot_tools', 'gclient.py')
1827 input_api.subprocess.check_output(
1828 [input_api.python_executable, gclient_path, 'verify'],
1829 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471830 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201831 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471832 return [output_api.PresubmitError(
1833 'DEPS file must have only git dependencies.',
1834 long_text=error.output)]
1835
1836
Mario Sanchez Prada2472cab2019-09-18 10:58:311837def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1838 type_name, message):
1839 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1840
1841 Returns an string composed of the name of the file, the line number where the
1842 match has been found and the additional text passed as |message| in case the
1843 target type name matches the text inside the line passed as parameter.
1844 """
Peng Huang9c5949a02020-06-11 19:20:541845 result = []
1846
1847 if line.endswith(" nocheck"):
1848 return result
1849
Mario Sanchez Prada2472cab2019-09-18 10:58:311850 matched = False
1851 if type_name[0:1] == '/':
1852 regex = type_name[1:]
1853 if input_api.re.search(regex, line):
1854 matched = True
1855 elif type_name in line:
1856 matched = True
1857
Mario Sanchez Prada2472cab2019-09-18 10:58:311858 if matched:
1859 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1860 for message_line in message:
1861 result.append(' %s' % message_line)
1862
1863 return result
1864
1865
[email protected]127f18ec2012-06-16 05:05:591866def _CheckNoBannedFunctions(input_api, output_api):
1867 """Make sure that banned functions are not used."""
1868 warnings = []
1869 errors = []
1870
James Cook24a504192020-07-23 00:08:441871 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151872 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441873 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151874 if input_api.re.match(item, local_path):
1875 return True
1876 return False
1877
Peter K. Lee6c03ccff2019-07-15 14:40:051878 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541879 local_path = affected_file.LocalPath()
1880 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1881 return False
1882 basename = input_api.os_path.basename(local_path)
1883 if 'ios' in basename.split('_'):
1884 return True
1885 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1886 if sep and 'ios' in local_path.split(sep):
1887 return True
1888 return False
1889
wnwenbdc444e2016-05-25 13:44:151890 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311891 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1892 func_name, message)
1893 if problems:
wnwenbdc444e2016-05-25 13:44:151894 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311895 errors.extend(problems)
1896 else:
1897 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151898
Eric Stevensona9a980972017-09-23 00:04:411899 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1900 for f in input_api.AffectedFiles(file_filter=file_filter):
1901 for line_num, line in f.ChangedContents():
1902 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1903 CheckForMatch(f, line_num, line, func_name, message, error)
1904
[email protected]127f18ec2012-06-16 05:05:591905 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1906 for f in input_api.AffectedFiles(file_filter=file_filter):
1907 for line_num, line in f.ChangedContents():
1908 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151909 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591910
Peter K. Lee6c03ccff2019-07-15 14:40:051911 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541912 for line_num, line in f.ChangedContents():
1913 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1914 CheckForMatch(f, line_num, line, func_name, message, error)
1915
Peter K. Lee6c03ccff2019-07-15 14:40:051916 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1917 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1918 for line_num, line in f.ChangedContents():
1919 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1920 CheckForMatch(f, line_num, line, func_name, message, error)
1921
[email protected]127f18ec2012-06-16 05:05:591922 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1923 for f in input_api.AffectedFiles(file_filter=file_filter):
1924 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491925 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441926 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491927 continue
wnwenbdc444e2016-05-25 13:44:151928 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591929
1930 result = []
1931 if (warnings):
1932 result.append(output_api.PresubmitPromptWarning(
1933 'Banned functions were used.\n' + '\n'.join(warnings)))
1934 if (errors):
1935 result.append(output_api.PresubmitError(
1936 'Banned functions were used.\n' + '\n'.join(errors)))
1937 return result
1938
1939
Michael Thiessen44457642020-02-06 00:24:151940def _CheckAndroidNoBannedImports(input_api, output_api):
1941 """Make sure that banned java imports are not used."""
1942 errors = []
1943
1944 def IsException(path, exceptions):
1945 for exception in exceptions:
1946 if (path.startswith(exception)):
1947 return True
1948 return False
1949
1950 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1951 for f in input_api.AffectedFiles(file_filter=file_filter):
1952 for line_num, line in f.ChangedContents():
1953 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1954 if IsException(f.LocalPath(), exceptions):
1955 continue;
1956 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1957 'import ' + import_name, message)
1958 if problems:
1959 errors.extend(problems)
1960 result = []
1961 if (errors):
1962 result.append(output_api.PresubmitError(
1963 'Banned imports were used.\n' + '\n'.join(errors)))
1964 return result
1965
1966
Mario Sanchez Prada2472cab2019-09-18 10:58:311967def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1968 """Make sure that old Mojo types are not used."""
1969 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571970 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311971
Mario Sanchez Pradaaab91382019-12-19 08:57:091972 # For any path that is not an "ok" or an "error" path, a warning will be
1973 # raised if deprecated mojo types are found.
1974 ok_paths = ['components/arc']
1975 error_paths = ['third_party/blink', 'content']
1976
Mario Sanchez Prada2472cab2019-09-18 10:58:311977 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1978 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571979 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091980 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311981 continue
1982
1983 for line_num, line in f.ChangedContents():
1984 for func_name, message in _DEPRECATED_MOJO_TYPES:
1985 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1986 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571987
Mario Sanchez Prada2472cab2019-09-18 10:58:311988 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091989 # Raise errors inside |error_paths| and warnings everywhere else.
1990 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571991 errors.extend(problems)
1992 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311993 warnings.extend(problems)
1994
1995 result = []
1996 if (warnings):
1997 result.append(output_api.PresubmitPromptWarning(
1998 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571999 if (errors):
2000 result.append(output_api.PresubmitError(
2001 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312002 return result
2003
2004
[email protected]6c063c62012-07-11 19:11:062005def _CheckNoPragmaOnce(input_api, output_api):
2006 """Make sure that banned functions are not used."""
2007 files = []
2008 pattern = input_api.re.compile(r'^#pragma\s+once',
2009 input_api.re.MULTILINE)
2010 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2011 if not f.LocalPath().endswith('.h'):
2012 continue
2013 contents = input_api.ReadFile(f)
2014 if pattern.search(contents):
2015 files.append(f)
2016
2017 if files:
2018 return [output_api.PresubmitError(
2019 'Do not use #pragma once in header files.\n'
2020 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2021 files)]
2022 return []
2023
[email protected]127f18ec2012-06-16 05:05:592024
[email protected]e7479052012-09-19 00:26:122025def _CheckNoTrinaryTrueFalse(input_api, output_api):
2026 """Checks to make sure we don't introduce use of foo ? true : false."""
2027 problems = []
2028 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2029 for f in input_api.AffectedFiles():
2030 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2031 continue
2032
2033 for line_num, line in f.ChangedContents():
2034 if pattern.match(line):
2035 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2036
2037 if not problems:
2038 return []
2039 return [output_api.PresubmitPromptWarning(
2040 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2041 '\n'.join(problems))]
2042
2043
[email protected]55f9f382012-07-31 11:02:182044def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282045 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182046 change. Breaking - rules is an error, breaking ! rules is a
2047 warning.
2048 """
mohan.reddyf21db962014-10-16 12:26:472049 import sys
[email protected]55f9f382012-07-31 11:02:182050 # We need to wait until we have an input_api object and use this
2051 # roundabout construct to import checkdeps because this file is
2052 # eval-ed and thus doesn't have __file__.
2053 original_sys_path = sys.path
2054 try:
2055 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472056 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182057 import checkdeps
[email protected]55f9f382012-07-31 11:02:182058 from rules import Rule
2059 finally:
2060 # Restore sys.path to what it was before.
2061 sys.path = original_sys_path
2062
2063 added_includes = []
rhalavati08acd232017-04-03 07:23:282064 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242065 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182066 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062067 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502068 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082069 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062070 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502071 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082072 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062073 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502074 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082075 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182076
[email protected]26385172013-05-09 23:11:352077 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182078
2079 error_descriptions = []
2080 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282081 error_subjects = set()
2082 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182083 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2084 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082085 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182086 description_with_path = '%s\n %s' % (path, rule_description)
2087 if rule_type == Rule.DISALLOW:
2088 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282089 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182090 else:
2091 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282092 warning_subjects.add("#includes")
2093
2094 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2095 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082096 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282097 description_with_path = '%s\n %s' % (path, rule_description)
2098 if rule_type == Rule.DISALLOW:
2099 error_descriptions.append(description_with_path)
2100 error_subjects.add("imports")
2101 else:
2102 warning_descriptions.append(description_with_path)
2103 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182104
Jinsuk Kim5a092672017-10-24 22:42:242105 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022106 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082107 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242108 description_with_path = '%s\n %s' % (path, rule_description)
2109 if rule_type == Rule.DISALLOW:
2110 error_descriptions.append(description_with_path)
2111 error_subjects.add("imports")
2112 else:
2113 warning_descriptions.append(description_with_path)
2114 warning_subjects.add("imports")
2115
[email protected]55f9f382012-07-31 11:02:182116 results = []
2117 if error_descriptions:
2118 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282119 'You added one or more %s that violate checkdeps rules.'
2120 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182121 error_descriptions))
2122 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422123 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282124 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182125 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282126 '%s? See relevant DEPS file(s) for details and contacts.' %
2127 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182128 warning_descriptions))
2129 return results
2130
2131
[email protected]fbcafe5a2012-08-08 15:31:222132def _CheckFilePermissions(input_api, output_api):
2133 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152134 if input_api.platform == 'win32':
2135 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292136 checkperms_tool = input_api.os_path.join(
2137 input_api.PresubmitLocalPath(),
2138 'tools', 'checkperms', 'checkperms.py')
2139 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472140 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392141 with input_api.CreateTemporaryFile() as file_list:
2142 for f in input_api.AffectedFiles():
2143 # checkperms.py file/directory arguments must be relative to the
2144 # repository.
2145 file_list.write(f.LocalPath() + '\n')
2146 file_list.close()
2147 args += ['--file-list', file_list.name]
2148 try:
2149 input_api.subprocess.check_output(args)
2150 return []
2151 except input_api.subprocess.CalledProcessError as error:
2152 return [output_api.PresubmitError(
2153 'checkperms.py failed:',
2154 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222155
2156
robertocn832f5992017-01-04 19:01:302157def _CheckTeamTags(input_api, output_api):
2158 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2159 checkteamtags_tool = input_api.os_path.join(
2160 input_api.PresubmitLocalPath(),
2161 'tools', 'checkteamtags', 'checkteamtags.py')
2162 args = [input_api.python_executable, checkteamtags_tool,
2163 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222164 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302165 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2166 'OWNERS']
2167 try:
2168 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052169 warnings = input_api.subprocess.check_output(args + files).splitlines()
2170 if warnings:
2171 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302172 return []
2173 except input_api.subprocess.CalledProcessError as error:
2174 return [output_api.PresubmitError(
2175 'checkteamtags.py failed:',
2176 long_text=error.output)]
2177
2178
[email protected]c8278b32012-10-30 20:35:492179def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2180 """Makes sure we don't include ui/aura/window_property.h
2181 in header files.
2182 """
2183 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2184 errors = []
2185 for f in input_api.AffectedFiles():
2186 if not f.LocalPath().endswith('.h'):
2187 continue
2188 for line_num, line in f.ChangedContents():
2189 if pattern.match(line):
2190 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2191
2192 results = []
2193 if errors:
2194 results.append(output_api.PresubmitError(
2195 'Header files should not include ui/aura/window_property.h', errors))
2196 return results
2197
2198
[email protected]70ca77752012-11-20 03:45:032199def _CheckForVersionControlConflictsInFile(input_api, f):
2200 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2201 errors = []
2202 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162203 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232204 # First-level headers in markdown look a lot like version control
2205 # conflict markers. http://daringfireball.net/projects/markdown/basics
2206 continue
[email protected]70ca77752012-11-20 03:45:032207 if pattern.match(line):
2208 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2209 return errors
2210
2211
2212def _CheckForVersionControlConflicts(input_api, output_api):
2213 """Usually this is not intentional and will cause a compile failure."""
2214 errors = []
2215 for f in input_api.AffectedFiles():
2216 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2217
2218 results = []
2219 if errors:
2220 results.append(output_api.PresubmitError(
2221 'Version control conflict markers found, please resolve.', errors))
2222 return results
2223
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202224
estadee17314a02017-01-12 16:22:162225def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2226 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2227 errors = []
2228 for f in input_api.AffectedFiles():
2229 for line_num, line in f.ChangedContents():
2230 if pattern.search(line):
2231 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2232
2233 results = []
2234 if errors:
2235 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502236 'Found Google support URL addressed by answer number. Please replace '
2237 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162238 return results
2239
[email protected]70ca77752012-11-20 03:45:032240
[email protected]06e6d0ff2012-12-11 01:36:442241def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2242 def FilterFile(affected_file):
2243 """Filter function for use with input_api.AffectedSourceFiles,
2244 below. This filters out everything except non-test files from
2245 top-level directories that generally speaking should not hard-code
2246 service URLs (e.g. src/android_webview/, src/content/ and others).
2247 """
2248 return input_api.FilterSourceFile(
2249 affected_file,
James Cook24a504192020-07-23 00:08:442250 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2251 files_to_skip=(_EXCLUDED_PATHS +
2252 _TEST_CODE_EXCLUDED_PATHS +
2253 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442254
reillyi38965732015-11-16 18:27:332255 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2256 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462257 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2258 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442259 problems = [] # items are (filename, line_number, line)
2260 for f in input_api.AffectedSourceFiles(FilterFile):
2261 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462262 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442263 problems.append((f.LocalPath(), line_num, line))
2264
2265 if problems:
[email protected]f7051d52013-04-02 18:31:422266 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442267 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582268 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442269 [' %s:%d: %s' % (
2270 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032271 else:
2272 return []
[email protected]06e6d0ff2012-12-11 01:36:442273
2274
James Cook6b6597c2019-11-06 22:05:292275def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2276 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2277 def FileFilter(affected_file):
2278 """Includes directories known to be Chrome OS only."""
2279 return input_api.FilterSourceFile(
2280 affected_file,
James Cook24a504192020-07-23 00:08:442281 files_to_check=('^ash/',
2282 '^chromeos/', # Top-level src/chromeos.
2283 '/chromeos/', # Any path component.
2284 '^components/arc',
2285 '^components/exo'),
2286 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292287
2288 prefs = []
2289 priority_prefs = []
2290 for f in input_api.AffectedFiles(file_filter=FileFilter):
2291 for line_num, line in f.ChangedContents():
2292 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2293 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2294 prefs.append(' %s' % line)
2295 if input_api.re.search(
2296 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2297 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2298 priority_prefs.append(' %s' % line)
2299
2300 results = []
2301 if (prefs):
2302 results.append(output_api.PresubmitPromptWarning(
2303 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2304 'by browser sync settings. If these prefs should be controlled by OS '
2305 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2306 if (priority_prefs):
2307 results.append(output_api.PresubmitPromptWarning(
2308 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2309 'controlled by browser sync settings. If these prefs should be '
2310 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2311 'instead.\n' + '\n'.join(prefs)))
2312 return results
2313
2314
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492315# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272316def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2317 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312318 The native_client_sdk directory is excluded because it has auto-generated PNG
2319 files for documentation.
[email protected]d2530012013-01-25 16:39:272320 """
[email protected]d2530012013-01-25 16:39:272321 errors = []
James Cook24a504192020-07-23 00:08:442322 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2323 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312324 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442325 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312326 for f in input_api.AffectedFiles(include_deletes=False,
2327 file_filter=file_filter):
2328 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272329
2330 results = []
2331 if errors:
2332 results.append(output_api.PresubmitError(
2333 'The name of PNG files should not have abbreviations. \n'
2334 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2335 'Contact [email protected] if you have questions.', errors))
2336 return results
2337
2338
Daniel Cheng4dcdb6b2017-04-13 08:30:172339def _ExtractAddRulesFromParsedDeps(parsed_deps):
2340 """Extract the rules that add dependencies from a parsed DEPS file.
2341
2342 Args:
2343 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2344 add_rules = set()
2345 add_rules.update([
2346 rule[1:] for rule in parsed_deps.get('include_rules', [])
2347 if rule.startswith('+') or rule.startswith('!')
2348 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502349 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172350 {}).iteritems():
2351 add_rules.update([
2352 rule[1:] for rule in rules
2353 if rule.startswith('+') or rule.startswith('!')
2354 ])
2355 return add_rules
2356
2357
2358def _ParseDeps(contents):
2359 """Simple helper for parsing DEPS files."""
2360 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172361 class _VarImpl:
2362
2363 def __init__(self, local_scope):
2364 self._local_scope = local_scope
2365
2366 def Lookup(self, var_name):
2367 """Implements the Var syntax."""
2368 try:
2369 return self._local_scope['vars'][var_name]
2370 except KeyError:
2371 raise Exception('Var is not defined: %s' % var_name)
2372
2373 local_scope = {}
2374 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172375 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592376 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172377 }
2378 exec contents in global_scope, local_scope
2379 return local_scope
2380
2381
2382def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082383 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412384 a set of DEPS entries that we should look up.
2385
2386 For a directory (rather than a specific filename) we fake a path to
2387 a specific filename by adding /DEPS. This is chosen as a file that
2388 will seldom or never be subject to per-file include_rules.
2389 """
[email protected]2b438d62013-11-14 17:54:142390 # We ignore deps entries on auto-generated directories.
2391 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082392
Daniel Cheng4dcdb6b2017-04-13 08:30:172393 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2394 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2395
2396 added_deps = new_deps.difference(old_deps)
2397
[email protected]2b438d62013-11-14 17:54:142398 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172399 for added_dep in added_deps:
2400 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2401 continue
2402 # Assume that a rule that ends in .h is a rule for a specific file.
2403 if added_dep.endswith('.h'):
2404 results.add(added_dep)
2405 else:
2406 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082407 return results
2408
2409
[email protected]e871964c2013-05-13 14:14:552410def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2411 """When a dependency prefixed with + is added to a DEPS file, we
2412 want to make sure that the change is reviewed by an OWNER of the
2413 target file or directory, to avoid layering violations from being
2414 introduced. This check verifies that this happens.
2415 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172416 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242417
2418 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492419 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242420 for f in input_api.AffectedFiles(include_deletes=False,
2421 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552422 filename = input_api.os_path.basename(f.LocalPath())
2423 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172424 virtual_depended_on_files.update(_CalculateAddedDeps(
2425 input_api.os_path,
2426 '\n'.join(f.OldContents()),
2427 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552428
[email protected]e871964c2013-05-13 14:14:552429 if not virtual_depended_on_files:
2430 return []
2431
2432 if input_api.is_committing:
2433 if input_api.tbr:
2434 return [output_api.PresubmitNotifyResult(
2435 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272436 if input_api.dry_run:
2437 return [output_api.PresubmitNotifyResult(
2438 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552439 if not input_api.change.issue:
2440 return [output_api.PresubmitError(
2441 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402442 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552443 output = output_api.PresubmitError
2444 else:
2445 output = output_api.PresubmitNotifyResult
2446
2447 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502448 owner_email, reviewers = (
2449 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2450 input_api,
2451 owners_db.email_regexp,
2452 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552453
2454 owner_email = owner_email or input_api.change.author_email
2455
[email protected]de4f7d22013-05-23 14:27:462456 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512457 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462458 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552459 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2460 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412461
2462 # We strip the /DEPS part that was added by
2463 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2464 # directory.
2465 def StripDeps(path):
2466 start_deps = path.rfind('/DEPS')
2467 if start_deps != -1:
2468 return path[:start_deps]
2469 else:
2470 return path
2471 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552472 for path in missing_files]
2473
2474 if unapproved_dependencies:
2475 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152476 output('You need LGTM from owners of depends-on paths in DEPS that were '
2477 'modified in this CL:\n %s' %
2478 '\n '.join(sorted(unapproved_dependencies)))]
2479 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2480 output_list.append(output(
2481 'Suggested missing target path OWNERS:\n %s' %
2482 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552483 return output_list
2484
2485 return []
2486
2487
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492488# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402489def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492490 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442491 files_to_skip = (_EXCLUDED_PATHS +
2492 _TEST_CODE_EXCLUDED_PATHS +
2493 input_api.DEFAULT_FILES_TO_SKIP +
2494 (r"^base[\\/]logging\.h$",
2495 r"^base[\\/]logging\.cc$",
2496 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2497 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2498 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2499 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2500 r"startup_browser_creator\.cc$",
2501 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2502 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2503 r"diagnostics_writer\.cc$",
2504 r"^chrome[\\/]chrome_cleaner[\\/].*",
2505 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2506 r"dll_hash_main\.cc$",
2507 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2508 r"^chromecast[\\/]",
2509 r"^cloud_print[\\/]",
2510 r"^components[\\/]browser_watcher[\\/]"
2511 r"dump_stability_report_main_win.cc$",
2512 r"^components[\\/]media_control[\\/]renderer[\\/]"
2513 r"media_playback_options\.cc$",
2514 r"^components[\\/]zucchini[\\/].*",
2515 # TODO(peter): Remove exception. https://crbug.com/534537
2516 r"^content[\\/]browser[\\/]notifications[\\/]"
2517 r"notification_event_dispatcher_impl\.cc$",
2518 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2519 r"gl_helper_benchmark\.cc$",
2520 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2521 r"^courgette[\\/]courgette_tool\.cc$",
2522 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2523 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2524 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2525 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2526 r"^ipc[\\/]ipc_logging\.cc$",
2527 r"^native_client_sdk[\\/]",
2528 r"^remoting[\\/]base[\\/]logging\.h$",
2529 r"^remoting[\\/]host[\\/].*",
2530 r"^sandbox[\\/]linux[\\/].*",
2531 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2532 r"dump_file_system.cc$",
2533 r"^tools[\\/]",
2534 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2535 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2536 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2537 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2538 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402539 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442540 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402541
thomasanderson625d3932017-03-29 07:16:582542 log_info = set([])
2543 printf = set([])
[email protected]85218562013-11-22 07:41:402544
2545 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582546 for _, line in f.ChangedContents():
2547 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2548 log_info.add(f.LocalPath())
2549 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2550 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372551
thomasanderson625d3932017-03-29 07:16:582552 if input_api.re.search(r"\bprintf\(", line):
2553 printf.add(f.LocalPath())
2554 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2555 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402556
2557 if log_info:
2558 return [output_api.PresubmitError(
2559 'These files spam the console log with LOG(INFO):',
2560 items=log_info)]
2561 if printf:
2562 return [output_api.PresubmitError(
2563 'These files spam the console log with printf/fprintf:',
2564 items=printf)]
2565 return []
2566
2567
[email protected]49aa76a2013-12-04 06:59:162568def _CheckForAnonymousVariables(input_api, output_api):
2569 """These types are all expected to hold locks while in scope and
2570 so should never be anonymous (which causes them to be immediately
2571 destroyed)."""
2572 they_who_must_be_named = [
2573 'base::AutoLock',
2574 'base::AutoReset',
2575 'base::AutoUnlock',
2576 'SkAutoAlphaRestore',
2577 'SkAutoBitmapShaderInstall',
2578 'SkAutoBlitterChoose',
2579 'SkAutoBounderCommit',
2580 'SkAutoCallProc',
2581 'SkAutoCanvasRestore',
2582 'SkAutoCommentBlock',
2583 'SkAutoDescriptor',
2584 'SkAutoDisableDirectionCheck',
2585 'SkAutoDisableOvalCheck',
2586 'SkAutoFree',
2587 'SkAutoGlyphCache',
2588 'SkAutoHDC',
2589 'SkAutoLockColors',
2590 'SkAutoLockPixels',
2591 'SkAutoMalloc',
2592 'SkAutoMaskFreeImage',
2593 'SkAutoMutexAcquire',
2594 'SkAutoPathBoundsUpdate',
2595 'SkAutoPDFRelease',
2596 'SkAutoRasterClipValidate',
2597 'SkAutoRef',
2598 'SkAutoTime',
2599 'SkAutoTrace',
2600 'SkAutoUnref',
2601 ]
2602 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2603 # bad: base::AutoLock(lock.get());
2604 # not bad: base::AutoLock lock(lock.get());
2605 bad_pattern = input_api.re.compile(anonymous)
2606 # good: new base::AutoLock(lock.get())
2607 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2608 errors = []
2609
2610 for f in input_api.AffectedFiles():
2611 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2612 continue
2613 for linenum, line in f.ChangedContents():
2614 if bad_pattern.search(line) and not good_pattern.search(line):
2615 errors.append('%s:%d' % (f.LocalPath(), linenum))
2616
2617 if errors:
2618 return [output_api.PresubmitError(
2619 'These lines create anonymous variables that need to be named:',
2620 items=errors)]
2621 return []
2622
2623
Peter Kasting4844e46e2018-02-23 07:27:102624def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532625 # Returns whether |template_str| is of the form <T, U...> for some types T
2626 # and U. Assumes that |template_str| is already in the form <...>.
2627 def HasMoreThanOneArg(template_str):
2628 # Level of <...> nesting.
2629 nesting = 0
2630 for c in template_str:
2631 if c == '<':
2632 nesting += 1
2633 elif c == '>':
2634 nesting -= 1
2635 elif c == ',' and nesting == 1:
2636 return True
2637 return False
2638
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492639 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102640 sources = lambda affected_file: input_api.FilterSourceFile(
2641 affected_file,
James Cook24a504192020-07-23 00:08:442642 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2643 input_api.DEFAULT_FILES_TO_SKIP),
2644 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552645
2646 # Pattern to capture a single "<...>" block of template arguments. It can
2647 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2648 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2649 # latter would likely require counting that < and > match, which is not
2650 # expressible in regular languages. Should the need arise, one can introduce
2651 # limited counting (matching up to a total number of nesting depth), which
2652 # should cover all practical cases for already a low nesting limit.
2653 template_arg_pattern = (
2654 r'<[^>]*' # Opening block of <.
2655 r'>([^<]*>)?') # Closing block of >.
2656 # Prefix expressing that whatever follows is not already inside a <...>
2657 # block.
2658 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102659 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552660 not_inside_template_arg_pattern
2661 + r'\bstd::unique_ptr'
2662 + template_arg_pattern
2663 + r'\(\)')
2664
2665 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2666 template_arg_no_array_pattern = (
2667 r'<[^>]*[^]]' # Opening block of <.
2668 r'>([^(<]*[^]]>)?') # Closing block of >.
2669 # Prefix saying that what follows is the start of an expression.
2670 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2671 # Suffix saying that what follows are call parentheses with a non-empty list
2672 # of arguments.
2673 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532674 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552675 return_construct_pattern = input_api.re.compile(
2676 start_of_expr_pattern
2677 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532678 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552679 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532680 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552681 + nonempty_arg_list_pattern)
2682
Vaclav Brozek851d9602018-04-04 16:13:052683 problems_constructor = []
2684 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102685 for f in input_api.AffectedSourceFiles(sources):
2686 for line_number, line in f.ChangedContents():
2687 # Disallow:
2688 # return std::unique_ptr<T>(foo);
2689 # bar = std::unique_ptr<T>(foo);
2690 # But allow:
2691 # return std::unique_ptr<T[]>(foo);
2692 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532693 # And also allow cases when the second template argument is present. Those
2694 # cases cannot be handled by std::make_unique:
2695 # return std::unique_ptr<T, U>(foo);
2696 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052697 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532698 return_construct_result = return_construct_pattern.search(line)
2699 if return_construct_result and not HasMoreThanOneArg(
2700 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052701 problems_constructor.append(
2702 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102703 # Disallow:
2704 # std::unique_ptr<T>()
2705 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052706 problems_nullptr.append(
2707 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2708
2709 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162710 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052711 errors.append(output_api.PresubmitError(
2712 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162713 problems_nullptr))
2714 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052715 errors.append(output_api.PresubmitError(
2716 'The following files use explicit std::unique_ptr constructor.'
2717 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162718 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102719 return errors
2720
2721
[email protected]999261d2014-03-03 20:08:082722def _CheckUserActionUpdate(input_api, output_api):
2723 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522724 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082725 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522726 # If actions.xml is already included in the changelist, the PRESUBMIT
2727 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082728 return []
2729
[email protected]999261d2014-03-03 20:08:082730 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2731 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522732 current_actions = None
[email protected]999261d2014-03-03 20:08:082733 for f in input_api.AffectedFiles(file_filter=file_filter):
2734 for line_num, line in f.ChangedContents():
2735 match = input_api.re.search(action_re, line)
2736 if match:
[email protected]2f92dec2014-03-07 19:21:522737 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2738 # loaded only once.
2739 if not current_actions:
2740 with open('tools/metrics/actions/actions.xml') as actions_f:
2741 current_actions = actions_f.read()
2742 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082743 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522744 action = 'name="{0}"'.format(action_name)
2745 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082746 return [output_api.PresubmitPromptWarning(
2747 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522748 'tools/metrics/actions/actions.xml. Please run '
2749 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082750 % (f.LocalPath(), line_num, action_name))]
2751 return []
2752
2753
Daniel Cheng13ca61a882017-08-25 15:11:252754def _ImportJSONCommentEater(input_api):
2755 import sys
2756 sys.path = sys.path + [input_api.os_path.join(
2757 input_api.PresubmitLocalPath(),
2758 'tools', 'json_comment_eater')]
2759 import json_comment_eater
2760 return json_comment_eater
2761
2762
[email protected]99171a92014-06-03 08:44:472763def _GetJSONParseError(input_api, filename, eat_comments=True):
2764 try:
2765 contents = input_api.ReadFile(filename)
2766 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252767 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132768 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472769
2770 input_api.json.loads(contents)
2771 except ValueError as e:
2772 return e
2773 return None
2774
2775
2776def _GetIDLParseError(input_api, filename):
2777 try:
2778 contents = input_api.ReadFile(filename)
2779 idl_schema = input_api.os_path.join(
2780 input_api.PresubmitLocalPath(),
2781 'tools', 'json_schema_compiler', 'idl_schema.py')
2782 process = input_api.subprocess.Popen(
2783 [input_api.python_executable, idl_schema],
2784 stdin=input_api.subprocess.PIPE,
2785 stdout=input_api.subprocess.PIPE,
2786 stderr=input_api.subprocess.PIPE,
2787 universal_newlines=True)
2788 (_, error) = process.communicate(input=contents)
2789 return error or None
2790 except ValueError as e:
2791 return e
2792
2793
2794def _CheckParseErrors(input_api, output_api):
2795 """Check that IDL and JSON files do not contain syntax errors."""
2796 actions = {
2797 '.idl': _GetIDLParseError,
2798 '.json': _GetJSONParseError,
2799 }
[email protected]99171a92014-06-03 08:44:472800 # Most JSON files are preprocessed and support comments, but these do not.
2801 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042802 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472803 ]
2804 # Only run IDL checker on files in these directories.
2805 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042806 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2807 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472808 ]
2809
2810 def get_action(affected_file):
2811 filename = affected_file.LocalPath()
2812 return actions.get(input_api.os_path.splitext(filename)[1])
2813
[email protected]99171a92014-06-03 08:44:472814 def FilterFile(affected_file):
2815 action = get_action(affected_file)
2816 if not action:
2817 return False
2818 path = affected_file.LocalPath()
2819
Erik Staab2dd72b12020-04-16 15:03:402820 if _MatchesFile(input_api,
2821 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2822 path):
[email protected]99171a92014-06-03 08:44:472823 return False
2824
2825 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162826 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472827 return False
2828 return True
2829
2830 results = []
2831 for affected_file in input_api.AffectedFiles(
2832 file_filter=FilterFile, include_deletes=False):
2833 action = get_action(affected_file)
2834 kwargs = {}
2835 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162836 _MatchesFile(input_api, json_no_comments_patterns,
2837 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472838 kwargs['eat_comments'] = False
2839 parse_error = action(input_api,
2840 affected_file.AbsoluteLocalPath(),
2841 **kwargs)
2842 if parse_error:
2843 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2844 (affected_file.LocalPath(), parse_error)))
2845 return results
2846
2847
[email protected]760deea2013-12-10 19:33:492848def _CheckJavaStyle(input_api, output_api):
2849 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472850 import sys
[email protected]760deea2013-12-10 19:33:492851 original_sys_path = sys.path
2852 try:
2853 sys.path = sys.path + [input_api.os_path.join(
2854 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2855 import checkstyle
2856 finally:
2857 # Restore sys.path to what it was before.
2858 sys.path = original_sys_path
2859
2860 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092861 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442862 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492863
2864
Nate Fischerdfd9812e2019-07-18 22:03:002865def _CheckPythonDevilInit(input_api, output_api):
2866 """Checks to make sure devil is initialized correctly in python scripts."""
2867 script_common_initialize_pattern = input_api.re.compile(
2868 r'script_common\.InitializeEnvironment\(')
2869 devil_env_config_initialize = input_api.re.compile(
2870 r'devil_env\.config\.Initialize\(')
2871
2872 errors = []
2873
2874 sources = lambda affected_file: input_api.FilterSourceFile(
2875 affected_file,
James Cook24a504192020-07-23 00:08:442876 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2877 (r'^build[\\/]android[\\/]devil_chromium\.py',
2878 r'^third_party[\\/].*',)),
2879 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002880
2881 for f in input_api.AffectedSourceFiles(sources):
2882 for line_num, line in f.ChangedContents():
2883 if (script_common_initialize_pattern.search(line) or
2884 devil_env_config_initialize.search(line)):
2885 errors.append("%s:%d" % (f.LocalPath(), line_num))
2886
2887 results = []
2888
2889 if errors:
2890 results.append(output_api.PresubmitError(
2891 'Devil initialization should always be done using '
2892 'devil_chromium.Initialize() in the chromium project, to use better '
2893 'defaults for dependencies (ex. up-to-date version of adb).',
2894 errors))
2895
2896 return results
2897
2898
Sean Kau46e29bc2017-08-28 16:31:162899def _MatchesFile(input_api, patterns, path):
2900 for pattern in patterns:
2901 if input_api.re.search(pattern, path):
2902 return True
2903 return False
2904
2905
Daniel Cheng7052cdf2017-11-21 19:23:292906def _GetOwnersFilesToCheckForIpcOwners(input_api):
2907 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172908
Daniel Cheng7052cdf2017-11-21 19:23:292909 Returns:
2910 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2911 contain to cover IPC-related files with noparent reviewer rules.
2912 """
2913 # Whether or not a file affects IPC is (mostly) determined by a simple list
2914 # of filename patterns.
dchenge07de812016-06-20 19:27:172915 file_patterns = [
palmerb19a0932017-01-24 04:00:312916 # Legacy IPC:
dchenge07de812016-06-20 19:27:172917 '*_messages.cc',
2918 '*_messages*.h',
2919 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312920 # Mojo IPC:
dchenge07de812016-06-20 19:27:172921 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472922 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172923 '*_struct_traits*.*',
2924 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312925 '*.typemap',
2926 # Android native IPC:
2927 '*.aidl',
2928 # Blink uses a different file naming convention:
2929 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472930 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172931 '*StructTraits*.*',
2932 '*TypeConverter*.*',
2933 ]
2934
scottmg7a6ed5ba2016-11-04 18:22:042935 # These third_party directories do not contain IPCs, but contain files
2936 # matching the above patterns, which trigger false positives.
2937 exclude_paths = [
2938 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162939 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232940 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292941 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542942 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162943 # These files are just used to communicate between class loaders running
2944 # in the same process.
2945 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572946 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2947
scottmg7a6ed5ba2016-11-04 18:22:042948 ]
2949
dchenge07de812016-06-20 19:27:172950 # Dictionary mapping an OWNERS file path to Patterns.
2951 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2952 # rules ) to a PatternEntry.
2953 # PatternEntry is a dictionary with two keys:
2954 # - 'files': the files that are matched by this pattern
2955 # - 'rules': the per-file rules needed for this pattern
2956 # For example, if we expect OWNERS file to contain rules for *.mojom and
2957 # *_struct_traits*.*, Patterns might look like this:
2958 # {
2959 # '*.mojom': {
2960 # 'files': ...,
2961 # 'rules': [
2962 # 'per-file *.mojom=set noparent',
2963 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2964 # ],
2965 # },
2966 # '*_struct_traits*.*': {
2967 # 'files': ...,
2968 # 'rules': [
2969 # 'per-file *_struct_traits*.*=set noparent',
2970 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2971 # ],
2972 # },
2973 # }
2974 to_check = {}
2975
Daniel Cheng13ca61a882017-08-25 15:11:252976 def AddPatternToCheck(input_file, pattern):
2977 owners_file = input_api.os_path.join(
2978 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2979 if owners_file not in to_check:
2980 to_check[owners_file] = {}
2981 if pattern not in to_check[owners_file]:
2982 to_check[owners_file][pattern] = {
2983 'files': [],
2984 'rules': [
2985 'per-file %s=set noparent' % pattern,
2986 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2987 ]
2988 }
Vaclav Brozekd5de76a2018-03-17 07:57:502989 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252990
dchenge07de812016-06-20 19:27:172991 # Iterate through the affected files to see what we actually need to check
2992 # for. We should only nag patch authors about per-file rules if a file in that
2993 # directory would match that pattern. If a directory only contains *.mojom
2994 # files and no *_messages*.h files, we should only nag about rules for
2995 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252996 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262997 # Manifest files don't have a strong naming convention. Instead, try to find
2998 # affected .cc and .h files which look like they contain a manifest
2999 # definition.
3000 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3001 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3002 if (manifest_pattern.search(f.LocalPath()) and not
3003 test_manifest_pattern.search(f.LocalPath())):
3004 # We expect all actual service manifest files to contain at least one
3005 # qualified reference to service_manager::Manifest.
3006 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253007 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173008 for pattern in file_patterns:
3009 if input_api.fnmatch.fnmatch(
3010 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043011 skip = False
3012 for exclude in exclude_paths:
3013 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3014 skip = True
3015 break
3016 if skip:
3017 continue
Daniel Cheng13ca61a882017-08-25 15:11:253018 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173019 break
3020
Daniel Cheng7052cdf2017-11-21 19:23:293021 return to_check
3022
3023
Wez17c66962020-04-29 15:26:033024def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3025 """Adds OWNERS files to check for correct Fuchsia security owners."""
3026
3027 file_patterns = [
3028 # Component specifications.
3029 '*.cml', # Component Framework v2.
3030 '*.cmx', # Component Framework v1.
3031
3032 # Fuchsia IDL protocol specifications.
3033 '*.fidl',
3034 ]
3035
3036 def AddPatternToCheck(input_file, pattern):
3037 owners_file = input_api.os_path.join(
3038 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3039 if owners_file not in to_check:
3040 to_check[owners_file] = {}
3041 if pattern not in to_check[owners_file]:
3042 to_check[owners_file][pattern] = {
3043 'files': [],
3044 'rules': [
3045 'per-file %s=set noparent' % pattern,
3046 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3047 ]
3048 }
3049 to_check[owners_file][pattern]['files'].append(input_file)
3050
3051 # Iterate through the affected files to see what we actually need to check
3052 # for. We should only nag patch authors about per-file rules if a file in that
3053 # directory would match that pattern.
3054 for f in input_api.AffectedFiles(include_deletes=False):
3055 for pattern in file_patterns:
3056 if input_api.fnmatch.fnmatch(
3057 input_api.os_path.basename(f.LocalPath()), pattern):
3058 AddPatternToCheck(f, pattern)
3059 break
3060
3061 return to_check
3062
3063
3064def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293065 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3066 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033067 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293068
3069 if to_check:
3070 # If there are any OWNERS files to check, there are IPC-related changes in
3071 # this CL. Auto-CC the review list.
3072 output_api.AppendCC('[email protected]')
3073
3074 # Go through the OWNERS files to check, filtering out rules that are already
3075 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173076 for owners_file, patterns in to_check.iteritems():
3077 try:
3078 with file(owners_file) as f:
3079 lines = set(f.read().splitlines())
3080 for entry in patterns.itervalues():
3081 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3082 ]
3083 except IOError:
3084 # No OWNERS file, so all the rules are definitely missing.
3085 continue
3086
3087 # All the remaining lines weren't found in OWNERS files, so emit an error.
3088 errors = []
3089 for owners_file, patterns in to_check.iteritems():
3090 missing_lines = []
3091 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503092 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173093 missing_lines.extend(entry['rules'])
3094 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3095 if missing_lines:
3096 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053097 'Because of the presence of files:\n%s\n\n'
3098 '%s needs the following %d lines added:\n\n%s' %
3099 ('\n'.join(files), owners_file, len(missing_lines),
3100 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173101
3102 results = []
3103 if errors:
vabrf5ce3bf92016-07-11 14:52:413104 if input_api.is_committing:
3105 output = output_api.PresubmitError
3106 else:
3107 output = output_api.PresubmitPromptWarning
3108 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593109 'Found OWNERS files that need to be updated for IPC security ' +
3110 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173111 long_text='\n\n'.join(errors)))
3112
3113 return results
3114
3115
Robert Sesek2c905332020-05-06 23:17:133116def _GetFilesUsingSecurityCriticalFunctions(input_api):
3117 """Checks affected files for changes to security-critical calls. This
3118 function checks the full change diff, to catch both additions/changes
3119 and removals.
3120
3121 Returns a dict keyed by file name, and the value is a set of detected
3122 functions.
3123 """
3124 # Map of function pretty name (displayed in an error) to the pattern to
3125 # match it with.
3126 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373127 'content::GetServiceSandboxType<>()':
3128 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133129 }
3130 _PATTERNS_TO_CHECK = {
3131 k: input_api.re.compile(v)
3132 for k, v in _PATTERNS_TO_CHECK.items()
3133 }
3134
3135 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3136 files_to_functions = {}
3137 for f in input_api.AffectedFiles():
3138 diff = f.GenerateScmDiff()
3139 for line in diff.split('\n'):
3140 # Not using just RightHandSideLines() because removing a
3141 # call to a security-critical function can be just as important
3142 # as adding or changing the arguments.
3143 if line.startswith('-') or (line.startswith('+') and
3144 not line.startswith('++')):
3145 for name, pattern in _PATTERNS_TO_CHECK.items():
3146 if pattern.search(line):
3147 path = f.LocalPath()
3148 if not path in files_to_functions:
3149 files_to_functions[path] = set()
3150 files_to_functions[path].add(name)
3151 return files_to_functions
3152
3153
3154def _CheckSecurityChanges(input_api, output_api):
3155 """Checks that changes involving security-critical functions are reviewed
3156 by the security team.
3157 """
3158 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3159 if len(files_to_functions):
3160 owners_db = input_api.owners_db
3161 owner_email, reviewers = (
3162 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3163 input_api,
3164 owners_db.email_regexp,
3165 approval_needed=input_api.is_committing))
3166
3167 # Load the OWNERS file for security changes.
3168 owners_file = 'ipc/SECURITY_OWNERS'
3169 security_owners = owners_db.owners_rooted_at_file(owners_file)
3170
3171 has_security_owner = any([owner in reviewers for owner in security_owners])
3172 if not has_security_owner:
3173 msg = 'The following files change calls to security-sensive functions\n' \
3174 'that need to be reviewed by {}.\n'.format(owners_file)
3175 for path, names in files_to_functions.items():
3176 msg += ' {}\n'.format(path)
3177 for name in names:
3178 msg += ' {}\n'.format(name)
3179 msg += '\n'
3180
3181 if input_api.is_committing:
3182 output = output_api.PresubmitError
3183 else:
3184 output = output_api.PresubmitNotifyResult
3185 return [output(msg)]
3186
3187 return []
3188
3189
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263190def _CheckSetNoParent(input_api, output_api):
3191 """Checks that set noparent is only used together with an OWNERS file in
3192 //build/OWNERS.setnoparent (see also
3193 //docs/code_reviews.md#owners-files-details)
3194 """
3195 errors = []
3196
3197 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3198 allowed_owners_files = set()
3199 with open(allowed_owners_files_file, 'r') as f:
3200 for line in f:
3201 line = line.strip()
3202 if not line or line.startswith('#'):
3203 continue
3204 allowed_owners_files.add(line)
3205
3206 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3207
3208 for f in input_api.AffectedFiles(include_deletes=False):
3209 if not f.LocalPath().endswith('OWNERS'):
3210 continue
3211
3212 found_owners_files = set()
3213 found_set_noparent_lines = dict()
3214
3215 # Parse the OWNERS file.
3216 for lineno, line in enumerate(f.NewContents(), 1):
3217 line = line.strip()
3218 if line.startswith('set noparent'):
3219 found_set_noparent_lines[''] = lineno
3220 if line.startswith('file://'):
3221 if line in allowed_owners_files:
3222 found_owners_files.add('')
3223 if line.startswith('per-file'):
3224 match = per_file_pattern.match(line)
3225 if match:
3226 glob = match.group(1).strip()
3227 directive = match.group(2).strip()
3228 if directive == 'set noparent':
3229 found_set_noparent_lines[glob] = lineno
3230 if directive.startswith('file://'):
3231 if directive in allowed_owners_files:
3232 found_owners_files.add(glob)
3233
3234 # Check that every set noparent line has a corresponding file:// line
3235 # listed in build/OWNERS.setnoparent.
3236 for set_noparent_line in found_set_noparent_lines:
3237 if set_noparent_line in found_owners_files:
3238 continue
3239 errors.append(' %s:%d' % (f.LocalPath(),
3240 found_set_noparent_lines[set_noparent_line]))
3241
3242 results = []
3243 if errors:
3244 if input_api.is_committing:
3245 output = output_api.PresubmitError
3246 else:
3247 output = output_api.PresubmitPromptWarning
3248 results.append(output(
3249 'Found the following "set noparent" restrictions in OWNERS files that '
3250 'do not include owners from build/OWNERS.setnoparent:',
3251 long_text='\n\n'.join(errors)))
3252 return results
3253
3254
jbriance9e12f162016-11-25 07:57:503255def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313256 """Checks that added or removed lines in non third party affected
3257 header files do not lead to new useless class or struct forward
3258 declaration.
jbriance9e12f162016-11-25 07:57:503259 """
3260 results = []
3261 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3262 input_api.re.MULTILINE)
3263 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3264 input_api.re.MULTILINE)
3265 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313266 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193267 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493268 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313269 continue
3270
jbriance9e12f162016-11-25 07:57:503271 if not f.LocalPath().endswith('.h'):
3272 continue
3273
3274 contents = input_api.ReadFile(f)
3275 fwd_decls = input_api.re.findall(class_pattern, contents)
3276 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3277
3278 useless_fwd_decls = []
3279 for decl in fwd_decls:
3280 count = sum(1 for _ in input_api.re.finditer(
3281 r'\b%s\b' % input_api.re.escape(decl), contents))
3282 if count == 1:
3283 useless_fwd_decls.append(decl)
3284
3285 if not useless_fwd_decls:
3286 continue
3287
3288 for line in f.GenerateScmDiff().splitlines():
3289 if (line.startswith('-') and not line.startswith('--') or
3290 line.startswith('+') and not line.startswith('++')):
3291 for decl in useless_fwd_decls:
3292 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3293 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243294 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503295 (f.LocalPath(), decl)))
3296 useless_fwd_decls.remove(decl)
3297
3298 return results
3299
Jinsong Fan91ebbbd2019-04-16 14:57:173300def _CheckAndroidDebuggableBuild(input_api, output_api):
3301 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3302 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3303 this is a debuggable build of Android.
3304 """
3305 build_type_check_pattern = input_api.re.compile(
3306 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3307
3308 errors = []
3309
3310 sources = lambda affected_file: input_api.FilterSourceFile(
3311 affected_file,
James Cook24a504192020-07-23 00:08:443312 files_to_skip=(_EXCLUDED_PATHS +
3313 _TEST_CODE_EXCLUDED_PATHS +
3314 input_api.DEFAULT_FILES_TO_SKIP +
3315 (r"^android_webview[\\/]support_library[\\/]"
3316 "boundary_interfaces[\\/]",
3317 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3318 r'^third_party[\\/].*',
3319 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3320 r"webview[\\/]chromium[\\/]License.*",)),
3321 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173322
3323 for f in input_api.AffectedSourceFiles(sources):
3324 for line_num, line in f.ChangedContents():
3325 if build_type_check_pattern.search(line):
3326 errors.append("%s:%d" % (f.LocalPath(), line_num))
3327
3328 results = []
3329
3330 if errors:
3331 results.append(output_api.PresubmitPromptWarning(
3332 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3333 ' Please use BuildInfo.isDebugAndroid() instead.',
3334 errors))
3335
3336 return results
jbriance9e12f162016-11-25 07:57:503337
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493338# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293339def _CheckAndroidToastUsage(input_api, output_api):
3340 """Checks that code uses org.chromium.ui.widget.Toast instead of
3341 android.widget.Toast (Chromium Toast doesn't force hardware
3342 acceleration on low-end devices, saving memory).
3343 """
3344 toast_import_pattern = input_api.re.compile(
3345 r'^import android\.widget\.Toast;$')
3346
3347 errors = []
3348
3349 sources = lambda affected_file: input_api.FilterSourceFile(
3350 affected_file,
James Cook24a504192020-07-23 00:08:443351 files_to_skip=(_EXCLUDED_PATHS +
3352 _TEST_CODE_EXCLUDED_PATHS +
3353 input_api.DEFAULT_FILES_TO_SKIP +
3354 (r'^chromecast[\\/].*',
3355 r'^remoting[\\/].*')),
3356 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293357
3358 for f in input_api.AffectedSourceFiles(sources):
3359 for line_num, line in f.ChangedContents():
3360 if toast_import_pattern.search(line):
3361 errors.append("%s:%d" % (f.LocalPath(), line_num))
3362
3363 results = []
3364
3365 if errors:
3366 results.append(output_api.PresubmitError(
3367 'android.widget.Toast usage is detected. Android toasts use hardware'
3368 ' acceleration, and can be\ncostly on low-end devices. Please use'
3369 ' org.chromium.ui.widget.Toast instead.\n'
3370 'Contact [email protected] if you have any questions.',
3371 errors))
3372
3373 return results
3374
3375
dgnaa68d5e2015-06-10 10:08:223376def _CheckAndroidCrLogUsage(input_api, output_api):
3377 """Checks that new logs using org.chromium.base.Log:
3378 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513379 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223380 """
pkotwicza1dd0b002016-05-16 14:41:043381
torne89540622017-03-24 19:41:303382 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043383 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303384 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043385 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303386 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043387 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3388 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093389 # The customtabs_benchmark is a small app that does not depend on Chromium
3390 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043391 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043392 ]
3393
dgnaa68d5e2015-06-10 10:08:223394 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123395 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3396 class_in_base_pattern = input_api.re.compile(
3397 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3398 has_some_log_import_pattern = input_api.re.compile(
3399 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223400 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553401 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223402 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463403 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553404 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223405
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463406 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443407 sources = lambda x: input_api.FilterSourceFile(x,
3408 files_to_check=[r'.*\.java$'],
3409 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123410
dgnaa68d5e2015-06-10 10:08:223411 tag_decl_errors = []
3412 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123413 tag_errors = []
dgn38736db2015-09-18 19:20:513414 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123415 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223416
3417 for f in input_api.AffectedSourceFiles(sources):
3418 file_content = input_api.ReadFile(f)
3419 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223420 # Per line checks
dgn87d9fb62015-06-12 09:15:123421 if (cr_log_import_pattern.search(file_content) or
3422 (class_in_base_pattern.search(file_content) and
3423 not has_some_log_import_pattern.search(file_content))):
3424 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223425 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553426 if rough_log_decl_pattern.search(line):
3427 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223428
3429 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123430 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223431 if match:
3432 has_modified_logs = True
3433
3434 # Make sure it uses "TAG"
3435 if not match.group('tag') == 'TAG':
3436 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123437 else:
3438 # Report non cr Log function calls in changed lines
3439 for line_num, line in f.ChangedContents():
3440 if log_call_pattern.search(line):
3441 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223442
3443 # Per file checks
3444 if has_modified_logs:
3445 # Make sure the tag is using the "cr" prefix and is not too long
3446 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513447 tag_name = match.group('name') if match else None
3448 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223449 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513450 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223451 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513452 elif '.' in tag_name:
3453 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223454
3455 results = []
3456 if tag_decl_errors:
3457 results.append(output_api.PresubmitPromptWarning(
3458 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513459 '"private static final String TAG = "<package tag>".\n'
3460 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223461 tag_decl_errors))
3462
3463 if tag_length_errors:
3464 results.append(output_api.PresubmitError(
3465 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513466 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223467 tag_length_errors))
3468
3469 if tag_errors:
3470 results.append(output_api.PresubmitPromptWarning(
3471 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3472 tag_errors))
3473
dgn87d9fb62015-06-12 09:15:123474 if util_log_errors:
dgn4401aa52015-04-29 16:26:173475 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123476 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3477 util_log_errors))
3478
dgn38736db2015-09-18 19:20:513479 if tag_with_dot_errors:
3480 results.append(output_api.PresubmitPromptWarning(
3481 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3482 tag_with_dot_errors))
3483
dgn4401aa52015-04-29 16:26:173484 return results
3485
3486
Yoland Yanb92fa522017-08-28 17:37:063487def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3488 """Checks that junit.framework.* is no longer used."""
3489 deprecated_junit_framework_pattern = input_api.re.compile(
3490 r'^import junit\.framework\..*;',
3491 input_api.re.MULTILINE)
3492 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443493 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063494 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133495 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063496 for line_num, line in f.ChangedContents():
3497 if deprecated_junit_framework_pattern.search(line):
3498 errors.append("%s:%d" % (f.LocalPath(), line_num))
3499
3500 results = []
3501 if errors:
3502 results.append(output_api.PresubmitError(
3503 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3504 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3505 ' if you have any question.', errors))
3506 return results
3507
3508
3509def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3510 """Checks that if new Java test classes have inheritance.
3511 Either the new test class is JUnit3 test or it is a JUnit4 test class
3512 with a base class, either case is undesirable.
3513 """
3514 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3515
3516 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443517 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063518 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133519 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063520 if not f.OldContents():
3521 class_declaration_start_flag = False
3522 for line_num, line in f.ChangedContents():
3523 if class_declaration_pattern.search(line):
3524 class_declaration_start_flag = True
3525 if class_declaration_start_flag and ' extends ' in line:
3526 errors.append('%s:%d' % (f.LocalPath(), line_num))
3527 if '{' in line:
3528 class_declaration_start_flag = False
3529
3530 results = []
3531 if errors:
3532 results.append(output_api.PresubmitPromptWarning(
3533 'The newly created files include Test classes that inherits from base'
3534 ' class. Please do not use inheritance in JUnit4 tests or add new'
3535 ' JUnit3 tests. Contact [email protected] if you have any'
3536 ' questions.', errors))
3537 return results
3538
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203539
yolandyan45001472016-12-21 21:12:423540def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3541 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3542 deprecated_annotation_import_pattern = input_api.re.compile(
3543 r'^import android\.test\.suitebuilder\.annotation\..*;',
3544 input_api.re.MULTILINE)
3545 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443546 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423547 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133548 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423549 for line_num, line in f.ChangedContents():
3550 if deprecated_annotation_import_pattern.search(line):
3551 errors.append("%s:%d" % (f.LocalPath(), line_num))
3552
3553 results = []
3554 if errors:
3555 results.append(output_api.PresubmitError(
3556 'Annotations in android.test.suitebuilder.annotation have been'
3557 ' deprecated since API level 24. Please use android.support.test.filters'
3558 ' from //third_party/android_support_test_runner:runner_java instead.'
3559 ' Contact [email protected] if you have any questions.', errors))
3560 return results
3561
3562
agrieve7b6479d82015-10-07 14:24:223563def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3564 """Checks if MDPI assets are placed in a correct directory."""
3565 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3566 ('/res/drawable/' in f.LocalPath() or
3567 '/res/drawable-ldrtl/' in f.LocalPath()))
3568 errors = []
3569 for f in input_api.AffectedFiles(include_deletes=False,
3570 file_filter=file_filter):
3571 errors.append(' %s' % f.LocalPath())
3572
3573 results = []
3574 if errors:
3575 results.append(output_api.PresubmitError(
3576 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3577 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3578 '/res/drawable-ldrtl/.\n'
3579 'Contact [email protected] if you have questions.', errors))
3580 return results
3581
3582
Nate Fischer535972b2017-09-16 01:06:183583def _CheckAndroidWebkitImports(input_api, output_api):
3584 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353585 android.webview.ValueCallback except in the WebView glue layer
3586 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183587 """
3588 valuecallback_import_pattern = input_api.re.compile(
3589 r'^import android\.webkit\.ValueCallback;$')
3590
3591 errors = []
3592
3593 sources = lambda affected_file: input_api.FilterSourceFile(
3594 affected_file,
James Cook24a504192020-07-23 00:08:443595 files_to_skip=(_EXCLUDED_PATHS +
3596 _TEST_CODE_EXCLUDED_PATHS +
3597 input_api.DEFAULT_FILES_TO_SKIP +
3598 (r'^android_webview[\\/]glue[\\/].*',
3599 r'^weblayer[\\/].*',)),
3600 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183601
3602 for f in input_api.AffectedSourceFiles(sources):
3603 for line_num, line in f.ChangedContents():
3604 if valuecallback_import_pattern.search(line):
3605 errors.append("%s:%d" % (f.LocalPath(), line_num))
3606
3607 results = []
3608
3609 if errors:
3610 results.append(output_api.PresubmitError(
3611 'android.webkit.ValueCallback usage is detected outside of the glue'
3612 ' layer. To stay compatible with the support library, android.webkit.*'
3613 ' classes should only be used inside the glue layer and'
3614 ' org.chromium.base.Callback should be used instead.',
3615 errors))
3616
3617 return results
3618
3619
Becky Zhou7c69b50992018-12-10 19:37:573620def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3621 """Checks Android XML styles """
3622 import sys
3623 original_sys_path = sys.path
3624 try:
3625 sys.path = sys.path + [input_api.os_path.join(
3626 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3627 import checkxmlstyle
3628 finally:
3629 # Restore sys.path to what it was before.
3630 sys.path = original_sys_path
3631
3632 if is_check_on_upload:
3633 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3634 else:
3635 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3636
3637
agrievef32bcc72016-04-04 14:57:403638class PydepsChecker(object):
3639 def __init__(self, input_api, pydeps_files):
3640 self._file_cache = {}
3641 self._input_api = input_api
3642 self._pydeps_files = pydeps_files
3643
3644 def _LoadFile(self, path):
3645 """Returns the list of paths within a .pydeps file relative to //."""
3646 if path not in self._file_cache:
3647 with open(path) as f:
3648 self._file_cache[path] = f.read()
3649 return self._file_cache[path]
3650
3651 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3652 """Returns an interable of paths within the .pydep, relativized to //."""
3653 os_path = self._input_api.os_path
3654 pydeps_dir = os_path.dirname(pydeps_path)
3655 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3656 if not l.startswith('*'))
3657 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3658
3659 def _CreateFilesToPydepsMap(self):
3660 """Returns a map of local_path -> list_of_pydeps."""
3661 ret = {}
3662 for pydep_local_path in self._pydeps_files:
3663 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3664 ret.setdefault(path, []).append(pydep_local_path)
3665 return ret
3666
3667 def ComputeAffectedPydeps(self):
3668 """Returns an iterable of .pydeps files that might need regenerating."""
3669 affected_pydeps = set()
3670 file_to_pydeps_map = None
3671 for f in self._input_api.AffectedFiles(include_deletes=True):
3672 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463673 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3674 # subrepositories. We can't figure out which files change, so re-check
3675 # all files.
3676 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383677 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3678 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403679 return self._pydeps_files
3680 elif local_path.endswith('.pydeps'):
3681 if local_path in self._pydeps_files:
3682 affected_pydeps.add(local_path)
3683 elif local_path.endswith('.py'):
3684 if file_to_pydeps_map is None:
3685 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3686 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3687 return affected_pydeps
3688
3689 def DetermineIfStale(self, pydeps_path):
3690 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413691 import difflib
John Budorick47ca3fe2018-02-10 00:53:103692 import os
3693
agrievef32bcc72016-04-04 14:57:403694 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033695 if old_pydeps_data:
3696 cmd = old_pydeps_data[1][1:].strip()
3697 old_contents = old_pydeps_data[2:]
3698 else:
3699 # A default cmd that should work in most cases (as long as pydeps filename
3700 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3701 # file is empty/new.
3702 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3703 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3704 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103705 env = dict(os.environ)
3706 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403707 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103708 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413709 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033710 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413711 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403712
3713
Tibor Goldschwendt360793f72019-06-25 18:23:493714def _ParseGclientArgs():
3715 args = {}
3716 with open('build/config/gclient_args.gni', 'r') as f:
3717 for line in f:
3718 line = line.strip()
3719 if not line or line.startswith('#'):
3720 continue
3721 attribute, value = line.split('=')
3722 args[attribute.strip()] = value.strip()
3723 return args
3724
3725
agrievef32bcc72016-04-04 14:57:403726def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3727 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403728 # This check is for Python dependency lists (.pydeps files), and involves
3729 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3730 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283731 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003732 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493733 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403734 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403735 results = []
3736 # First, check for new / deleted .pydeps.
3737 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033738 # Check whether we are running the presubmit check for a file in src.
3739 # f.LocalPath is relative to repo (src, or internal repo).
3740 # os_path.exists is relative to src repo.
3741 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3742 # to src and we can conclude that the pydeps is in src.
3743 if input_api.os_path.exists(f.LocalPath()):
3744 if f.LocalPath().endswith('.pydeps'):
3745 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3746 results.append(output_api.PresubmitError(
3747 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3748 'remove %s' % f.LocalPath()))
3749 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3750 results.append(output_api.PresubmitError(
3751 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3752 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403753
3754 if results:
3755 return results
3756
Mohamed Heikal7cd4d8312020-06-16 16:49:403757 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3758 affected_pydeps = set(checker.ComputeAffectedPydeps())
3759 affected_android_pydeps = affected_pydeps.intersection(
3760 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3761 if affected_android_pydeps and not is_android:
3762 results.append(output_api.PresubmitPromptOrNotify(
3763 'You have changed python files that may affect pydeps for android\n'
3764 'specific scripts. However, the relevant presumbit check cannot be\n'
3765 'run because you are not using an Android checkout. To validate that\n'
3766 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3767 'use the android-internal-presubmit optional trybot.\n'
3768 'Possibly stale pydeps files:\n{}'.format(
3769 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403770
Mohamed Heikal7cd4d8312020-06-16 16:49:403771 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3772 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403773 try:
phajdan.jr0d9878552016-11-04 10:49:413774 result = checker.DetermineIfStale(pydep_path)
3775 if result:
3776 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403777 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413778 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3779 'To regenerate, run:\n\n %s' %
3780 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403781 except input_api.subprocess.CalledProcessError as error:
3782 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3783 long_text=error.output)]
3784
3785 return results
3786
3787
glidere61efad2015-02-18 17:39:433788def _CheckSingletonInHeaders(input_api, output_api):
3789 """Checks to make sure no header files have |Singleton<|."""
3790 def FileFilter(affected_file):
3791 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443792 files_to_skip = (_EXCLUDED_PATHS +
3793 input_api.DEFAULT_FILES_TO_SKIP +
3794 (r"^base[\\/]memory[\\/]singleton\.h$",
3795 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3796 r"quic_singleton_impl\.h$"))
3797 return input_api.FilterSourceFile(affected_file,
3798 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433799
sergeyu34d21222015-09-16 00:11:443800 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433801 files = []
3802 for f in input_api.AffectedSourceFiles(FileFilter):
3803 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3804 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3805 contents = input_api.ReadFile(f)
3806 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243807 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433808 pattern.search(line)):
3809 files.append(f)
3810 break
3811
3812 if files:
yolandyandaabc6d2016-04-18 18:29:393813 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443814 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433815 'Please move them to an appropriate source file so that the ' +
3816 'template gets instantiated in a single compilation unit.',
3817 files) ]
3818 return []
3819
3820
[email protected]fd20b902014-05-09 02:14:533821_DEPRECATED_CSS = [
3822 # Values
3823 ( "-webkit-box", "flex" ),
3824 ( "-webkit-inline-box", "inline-flex" ),
3825 ( "-webkit-flex", "flex" ),
3826 ( "-webkit-inline-flex", "inline-flex" ),
3827 ( "-webkit-min-content", "min-content" ),
3828 ( "-webkit-max-content", "max-content" ),
3829
3830 # Properties
3831 ( "-webkit-background-clip", "background-clip" ),
3832 ( "-webkit-background-origin", "background-origin" ),
3833 ( "-webkit-background-size", "background-size" ),
3834 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443835 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533836
3837 # Functions
3838 ( "-webkit-gradient", "gradient" ),
3839 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3840 ( "-webkit-linear-gradient", "linear-gradient" ),
3841 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3842 ( "-webkit-radial-gradient", "radial-gradient" ),
3843 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3844]
3845
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203846
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493847# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243848def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533849 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253850 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343851 documentation and iOS CSS for dom distiller
3852 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253853 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533854 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493855 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443856 files_to_skip = (_EXCLUDED_PATHS +
3857 _TEST_CODE_EXCLUDED_PATHS +
3858 input_api.DEFAULT_FILES_TO_SKIP +
3859 (r"^chrome/common/extensions/docs",
3860 r"^chrome/docs",
3861 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3862 r"^components/neterror/resources/neterror.css",
3863 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253864 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443865 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533866 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3867 for line_num, line in fpath.ChangedContents():
3868 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023869 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533870 results.append(output_api.PresubmitError(
3871 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3872 (fpath.LocalPath(), line_num, deprecated_value, value)))
3873 return results
3874
mohan.reddyf21db962014-10-16 12:26:473875
rlanday6802cf632017-05-30 17:48:363876def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363877 bad_files = {}
3878 for f in input_api.AffectedFiles(include_deletes=False):
3879 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493880 not f.LocalPath().startswith('third_party/blink') and
3881 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363882 continue
3883
Daniel Bratell65b033262019-04-23 08:17:063884 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363885 continue
3886
Vaclav Brozekd5de76a2018-03-17 07:57:503887 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363888 if "#include" in line and "../" in line]
3889 if not relative_includes:
3890 continue
3891 bad_files[f.LocalPath()] = relative_includes
3892
3893 if not bad_files:
3894 return []
3895
3896 error_descriptions = []
3897 for file_path, bad_lines in bad_files.iteritems():
3898 error_description = file_path
3899 for line in bad_lines:
3900 error_description += '\n ' + line
3901 error_descriptions.append(error_description)
3902
3903 results = []
3904 results.append(output_api.PresubmitError(
3905 'You added one or more relative #include paths (including "../").\n'
3906 'These shouldn\'t be used because they can be used to include headers\n'
3907 'from code that\'s not correctly specified as a dependency in the\n'
3908 'relevant BUILD.gn file(s).',
3909 error_descriptions))
3910
3911 return results
3912
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Daniel Bratell65b033262019-04-23 08:17:063914def _CheckForCcIncludes(input_api, output_api):
3915 """Check that nobody tries to include a cc file. It's a relatively
3916 common error which results in duplicate symbols in object
3917 files. This may not always break the build until someone later gets
3918 very confusing linking errors."""
3919 results = []
3920 for f in input_api.AffectedFiles(include_deletes=False):
3921 # We let third_party code do whatever it wants
3922 if (f.LocalPath().startswith('third_party') and
3923 not f.LocalPath().startswith('third_party/blink') and
3924 not f.LocalPath().startswith('third_party\\blink')):
3925 continue
3926
3927 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3928 continue
3929
3930 for _, line in f.ChangedContents():
3931 if line.startswith('#include "'):
3932 included_file = line.split('"')[1]
3933 if _IsCPlusPlusFile(input_api, included_file):
3934 # The most common naming for external files with C++ code,
3935 # apart from standard headers, is to call them foo.inc, but
3936 # Chromium sometimes uses foo-inc.cc so allow that as well.
3937 if not included_file.endswith(('.h', '-inc.cc')):
3938 results.append(output_api.PresubmitError(
3939 'Only header files or .inc files should be included in other\n'
3940 'C++ files. Compiling the contents of a cc file more than once\n'
3941 'will cause duplicate information in the build which may later\n'
3942 'result in strange link_errors.\n' +
3943 f.LocalPath() + ':\n ' +
3944 line))
3945
3946 return results
3947
3948
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3950 if not isinstance(key, ast.Str):
3951 return 'Key at line %d must be a string literal' % key.lineno
3952 if not isinstance(value, ast.Dict):
3953 return 'Value at line %d must be a dict' % value.lineno
3954 if len(value.keys) != 1:
3955 return 'Dict at line %d must have single entry' % value.lineno
3956 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3957 return (
3958 'Entry at line %d must have a string literal \'filepath\' as key' %
3959 value.lineno)
3960 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133961
Takeshi Yoshinoe387aa32017-08-02 13:16:133962
Sergey Ulanov4af16052018-11-08 02:41:463963def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203964 if not isinstance(key, ast.Str):
3965 return 'Key at line %d must be a string literal' % key.lineno
3966 if not isinstance(value, ast.List):
3967 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463968 for element in value.elts:
3969 if not isinstance(element, ast.Str):
3970 return 'Watchlist elements on line %d is not a string' % key.lineno
3971 if not email_regex.match(element.s):
3972 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3973 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203974 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133975
Takeshi Yoshinoe387aa32017-08-02 13:16:133976
Sergey Ulanov4af16052018-11-08 02:41:463977def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203978 mismatch_template = (
3979 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3980 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133981
Sergey Ulanov4af16052018-11-08 02:41:463982 email_regex = input_api.re.compile(
3983 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3984
3985 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203986 i = 0
3987 last_key = ''
3988 while True:
3989 if i >= len(wd_dict.keys):
3990 if i >= len(w_dict.keys):
3991 return None
3992 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3993 elif i >= len(w_dict.keys):
3994 return (
3995 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133996
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203997 wd_key = wd_dict.keys[i]
3998 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133999
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204000 result = _CheckWatchlistDefinitionsEntrySyntax(
4001 wd_key, wd_dict.values[i], ast)
4002 if result is not None:
4003 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134004
Sergey Ulanov4af16052018-11-08 02:41:464005 result = _CheckWatchlistsEntrySyntax(
4006 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204007 if result is not None:
4008 return 'Bad entry in WATCHLISTS dict: %s' % result
4009
4010 if wd_key.s != w_key.s:
4011 return mismatch_template % (
4012 '%s at line %d' % (wd_key.s, wd_key.lineno),
4013 '%s at line %d' % (w_key.s, w_key.lineno))
4014
4015 if wd_key.s < last_key:
4016 return (
4017 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4018 (wd_key.lineno, w_key.lineno))
4019 last_key = wd_key.s
4020
4021 i = i + 1
4022
4023
Sergey Ulanov4af16052018-11-08 02:41:464024def _CheckWATCHLISTSSyntax(expression, input_api):
4025 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204026 if not isinstance(expression, ast.Expression):
4027 return 'WATCHLISTS file must contain a valid expression'
4028 dictionary = expression.body
4029 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4030 return 'WATCHLISTS file must have single dict with exactly two entries'
4031
4032 first_key = dictionary.keys[0]
4033 first_value = dictionary.values[0]
4034 second_key = dictionary.keys[1]
4035 second_value = dictionary.values[1]
4036
4037 if (not isinstance(first_key, ast.Str) or
4038 first_key.s != 'WATCHLIST_DEFINITIONS' or
4039 not isinstance(first_value, ast.Dict)):
4040 return (
4041 'The first entry of the dict in WATCHLISTS file must be '
4042 'WATCHLIST_DEFINITIONS dict')
4043
4044 if (not isinstance(second_key, ast.Str) or
4045 second_key.s != 'WATCHLISTS' or
4046 not isinstance(second_value, ast.Dict)):
4047 return (
4048 'The second entry of the dict in WATCHLISTS file must be '
4049 'WATCHLISTS dict')
4050
Sergey Ulanov4af16052018-11-08 02:41:464051 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134052
4053
4054def _CheckWATCHLISTS(input_api, output_api):
4055 for f in input_api.AffectedFiles(include_deletes=False):
4056 if f.LocalPath() == 'WATCHLISTS':
4057 contents = input_api.ReadFile(f, 'r')
4058
4059 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204060 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134061 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204062 # Get an AST tree for it and scan the tree for detailed style checking.
4063 expression = input_api.ast.parse(
4064 contents, filename='WATCHLISTS', mode='eval')
4065 except ValueError as e:
4066 return [output_api.PresubmitError(
4067 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4068 except SyntaxError as e:
4069 return [output_api.PresubmitError(
4070 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4071 except TypeError as e:
4072 return [output_api.PresubmitError(
4073 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134074
Sergey Ulanov4af16052018-11-08 02:41:464075 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204076 if result is not None:
4077 return [output_api.PresubmitError(result)]
4078 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134079
4080 return []
4081
4082
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194083def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4084 """Checks that newly added header files have corresponding GN changes.
4085 Note that this is only a heuristic. To be precise, run script:
4086 build/check_gn_headers.py.
4087 """
4088
4089 def headers(f):
4090 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444091 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194092
4093 new_headers = []
4094 for f in input_api.AffectedSourceFiles(headers):
4095 if f.Action() != 'A':
4096 continue
4097 new_headers.append(f.LocalPath())
4098
4099 def gn_files(f):
James Cook24a504192020-07-23 00:08:444100 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194101
4102 all_gn_changed_contents = ''
4103 for f in input_api.AffectedSourceFiles(gn_files):
4104 for _, line in f.ChangedContents():
4105 all_gn_changed_contents += line
4106
4107 problems = []
4108 for header in new_headers:
4109 basename = input_api.os_path.basename(header)
4110 if basename not in all_gn_changed_contents:
4111 problems.append(header)
4112
4113 if problems:
4114 return [output_api.PresubmitPromptWarning(
4115 'Missing GN changes for new header files', items=sorted(problems),
4116 long_text='Please double check whether newly added header files need '
4117 'corresponding changes in gn or gni files.\nThis checking is only a '
4118 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4119 'Read https://crbug.com/661774 for more info.')]
4120 return []
4121
4122
Michael Giuffridad3bc8672018-10-25 22:48:024123def _CheckCorrectProductNameInMessages(input_api, output_api):
4124 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4125
4126 This assumes we won't intentionally reference one product from the other
4127 product.
4128 """
4129 all_problems = []
4130 test_cases = [{
4131 "filename_postfix": "google_chrome_strings.grd",
4132 "correct_name": "Chrome",
4133 "incorrect_name": "Chromium",
4134 }, {
4135 "filename_postfix": "chromium_strings.grd",
4136 "correct_name": "Chromium",
4137 "incorrect_name": "Chrome",
4138 }]
4139
4140 for test_case in test_cases:
4141 problems = []
4142 filename_filter = lambda x: x.LocalPath().endswith(
4143 test_case["filename_postfix"])
4144
4145 # Check each new line. Can yield false positives in multiline comments, but
4146 # easier than trying to parse the XML because messages can have nested
4147 # children, and associating message elements with affected lines is hard.
4148 for f in input_api.AffectedSourceFiles(filename_filter):
4149 for line_num, line in f.ChangedContents():
4150 if "<message" in line or "<!--" in line or "-->" in line:
4151 continue
4152 if test_case["incorrect_name"] in line:
4153 problems.append(
4154 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4155
4156 if problems:
4157 message = (
4158 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4159 % (test_case["correct_name"], test_case["correct_name"],
4160 test_case["incorrect_name"]))
4161 all_problems.append(
4162 output_api.PresubmitPromptWarning(message, items=problems))
4163
4164 return all_problems
4165
4166
Dirk Pranke3c18a382019-03-15 01:07:514167def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4168 # TODO(crbug.com/941824): We need to make sure the entries in
4169 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4170 # so that users of //buildtools in other projects get the same tooling
4171 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4172 # support to gclient, we can eliminate the duplication and delete
4173 # this presubmit check.
4174
4175 # Update this regexp if new revisions are added to the files.
4176 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264177 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514178
4179 # If a user is changing one revision, they need to change the same
4180 # line in both files. This means that any given change should contain
4181 # exactly the same list of changed lines that match the regexps. The
4182 # replace(' ', '') call allows us to ignore whitespace changes to the
4183 # lines. The 'long_text' parameter to the error will contain the
4184 # list of changed lines in both files, which should make it easy enough
4185 # to spot the error without going overboard in this implementation.
4186 revs_changes = {
4187 'DEPS': {},
4188 'buildtools/DEPS': {},
4189 }
4190 long_text = ''
4191
4192 for f in input_api.AffectedFiles(
4193 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4194 for line_num, line in f.ChangedContents():
4195 if rev_regexp.search(line):
4196 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4197 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4198
4199 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4200 return [output_api.PresubmitError(
4201 'Change buildtools revisions in sync in both //DEPS and '
4202 '//buildtools/DEPS.', long_text=long_text + '\n')]
4203 else:
4204 return []
4205
4206
Daniel Bratell93eb6c62019-04-29 20:13:364207def _CheckForTooLargeFiles(input_api, output_api):
4208 """Avoid large files, especially binary files, in the repository since
4209 git doesn't scale well for those. They will be in everyone's repo
4210 clones forever, forever making Chromium slower to clone and work
4211 with."""
4212
4213 # Uploading files to cloud storage is not trivial so we don't want
4214 # to set the limit too low, but the upper limit for "normal" large
4215 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4216 # anything over 20 MB is exceptional.
4217 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4218
4219 too_large_files = []
4220 for f in input_api.AffectedFiles():
4221 # Check both added and modified files (but not deleted files).
4222 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384223 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364224 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4225 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4226
4227 if too_large_files:
4228 message = (
4229 'Do not commit large files to git since git scales badly for those.\n' +
4230 'Instead put the large files in cloud storage and use DEPS to\n' +
4231 'fetch them.\n' + '\n'.join(too_large_files)
4232 )
4233 return [output_api.PresubmitError(
4234 'Too large files found in commit', long_text=message + '\n')]
4235 else:
4236 return []
4237
Max Morozb47503b2019-08-08 21:03:274238
4239def _CheckFuzzTargets(input_api, output_api):
4240 """Checks specific for fuzz target sources."""
4241 EXPORTED_SYMBOLS = [
4242 'LLVMFuzzerInitialize',
4243 'LLVMFuzzerCustomMutator',
4244 'LLVMFuzzerCustomCrossOver',
4245 'LLVMFuzzerMutate',
4246 ]
4247
4248 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4249
4250 def FilterFile(affected_file):
4251 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444252 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4253 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274254
4255 return input_api.FilterSourceFile(
4256 affected_file,
James Cook24a504192020-07-23 00:08:444257 files_to_check=[files_to_check],
4258 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274259
4260 files_with_missing_header = []
4261 for f in input_api.AffectedSourceFiles(FilterFile):
4262 contents = input_api.ReadFile(f, 'r')
4263 if REQUIRED_HEADER in contents:
4264 continue
4265
4266 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4267 files_with_missing_header.append(f.LocalPath())
4268
4269 if not files_with_missing_header:
4270 return []
4271
4272 long_text = (
4273 'If you define any of the libFuzzer optional functions (%s), it is '
4274 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4275 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4276 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4277 'to access command line arguments passed to the fuzzer. Instead, prefer '
4278 'static initialization and shared resources as documented in '
4279 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4280 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4281 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4282 )
4283
4284 return [output_api.PresubmitPromptWarning(
4285 message="Missing '%s' in:" % REQUIRED_HEADER,
4286 items=files_with_missing_header,
4287 long_text=long_text)]
4288
4289
Mohamed Heikald048240a2019-11-12 16:57:374290def _CheckNewImagesWarning(input_api, output_api):
4291 """
4292 Warns authors who add images into the repo to make sure their images are
4293 optimized before committing.
4294 """
4295 images_added = False
4296 image_paths = []
4297 errors = []
4298 filter_lambda = lambda x: input_api.FilterSourceFile(
4299 x,
James Cook24a504192020-07-23 00:08:444300 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4301 + input_api.DEFAULT_FILES_TO_SKIP),
4302 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374303 )
4304 for f in input_api.AffectedFiles(
4305 include_deletes=False, file_filter=filter_lambda):
4306 local_path = f.LocalPath().lower()
4307 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4308 images_added = True
4309 image_paths.append(f)
4310 if images_added:
4311 errors.append(output_api.PresubmitPromptWarning(
4312 'It looks like you are trying to commit some images. If these are '
4313 'non-test-only images, please make sure to read and apply the tips in '
4314 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4315 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4316 'FYI only and will not block your CL on the CQ.', image_paths))
4317 return errors
4318
4319
dgnaa68d5e2015-06-10 10:08:224320def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574321 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224322 results = []
dgnaa68d5e2015-06-10 10:08:224323 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174324 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224325 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294326 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064327 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4328 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424329 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184330 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574331 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374332 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154333 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574334 return results
4335
4336def _AndroidSpecificOnCommitChecks(input_api, output_api):
4337 """Groups commit checks that target android code."""
4338 results = []
4339 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224340 return results
4341
Chris Hall59f8d0c72020-05-01 07:31:194342# TODO(chrishall): could we additionally match on any path owned by
4343# ui/accessibility/OWNERS ?
4344_ACCESSIBILITY_PATHS = (
4345 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4346 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4347 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4348 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4349 r"^content[\\/]browser[\\/]accessibility[\\/]",
4350 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4351 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4352 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4353 r"^ui[\\/]accessibility[\\/]",
4354 r"^ui[\\/]views[\\/]accessibility[\\/]",
4355)
4356
4357def _CheckAccessibilityRelnotesField(input_api, output_api):
4358 """Checks that commits to accessibility code contain an AX-Relnotes field in
4359 their commit message."""
4360 def FileFilter(affected_file):
4361 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444362 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194363
4364 # Only consider changes affecting accessibility paths.
4365 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4366 return []
4367
Akihiro Ota08108e542020-05-20 15:30:534368 # AX-Relnotes can appear in either the description or the footer.
4369 # When searching the description, require 'AX-Relnotes:' to appear at the
4370 # beginning of a line.
4371 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4372 description_has_relnotes = any(ax_regex.match(line)
4373 for line in input_api.change.DescriptionText().lower().splitlines())
4374
4375 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4376 'AX-Relnotes', [])
4377 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194378 return []
4379
4380 # TODO(chrishall): link to Relnotes documentation in message.
4381 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4382 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4383 "user-facing changes"
4384 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4385 "user-facing effects"
4386 "\n if this is confusing or annoying then please contact members "
4387 "of ui/accessibility/OWNERS.")
4388
4389 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224390
[email protected]22c9bd72011-03-27 16:47:394391def _CommonChecks(input_api, output_api):
4392 """Checks common to both upload and commit."""
4393 results = []
4394 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384395 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544396 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084397
4398 author = input_api.change.author_email
4399 if author and author not in _KNOWN_ROBOTS:
4400 results.extend(
4401 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4402
Chris Hall59f8d0c72020-05-01 07:31:194403 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194404 results.extend(
[email protected]760deea2013-12-10 19:33:494405 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234406 results.extend(
4407 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544408 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184409 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344410 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524411 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224412 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444413 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594414 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314415 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064416 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124417 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184418 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224419 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304420 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494421 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034422 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494423 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444424 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294425 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274426 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074427 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544428 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444429 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394430 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554431 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044432 results.extend(
4433 input_api.canned_checks.CheckChangeHasNoTabs(
4434 input_api,
4435 output_api,
4436 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404437 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164438 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084439 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244440 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474441 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044442 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054443 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144444 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234445 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434446 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404447 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154448 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034449 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134450 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264451 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504452 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364453 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064454 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134455 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434456 results.extend(input_api.RunTests(
4457 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264458 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124459 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024460 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514461 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364462 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004463 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514464 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244465
Vaclav Brozekcdc7defb2018-03-20 09:54:354466 for f in input_api.AffectedFiles():
4467 path, name = input_api.os_path.split(f.LocalPath())
4468 if name == 'PRESUBMIT.py':
4469 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004470 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4471 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074472 # The PRESUBMIT.py file (and the directory containing it) might
4473 # have been affected by being moved or removed, so only try to
4474 # run the tests if they still exist.
4475 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4476 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444477 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394478 return results
[email protected]1f7b4172010-01-28 01:17:344479
[email protected]b337cb5b2011-01-23 21:24:054480
[email protected]b8079ae4a2012-12-05 19:56:494481def _CheckPatchFiles(input_api, output_api):
4482 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4483 if f.LocalPath().endswith(('.orig', '.rej'))]
4484 if problems:
4485 return [output_api.PresubmitError(
4486 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034487 else:
4488 return []
[email protected]b8079ae4a2012-12-05 19:56:494489
4490
Kent Tamura5a8755d2017-06-29 23:37:074491def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214492 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4493 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4494 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074495 include_re = input_api.re.compile(
4496 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4497 extension_re = input_api.re.compile(r'\.[a-z]+$')
4498 errors = []
4499 for f in input_api.AffectedFiles():
4500 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4501 continue
4502 found_line_number = None
4503 found_macro = None
4504 for line_num, line in f.ChangedContents():
4505 match = macro_re.search(line)
4506 if match:
4507 found_line_number = line_num
4508 found_macro = match.group(2)
4509 break
4510 if not found_line_number:
4511 continue
4512
4513 found_include = False
4514 for line in f.NewContents():
4515 if include_re.search(line):
4516 found_include = True
4517 break
4518 if found_include:
4519 continue
4520
4521 if not f.LocalPath().endswith('.h'):
4522 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4523 try:
4524 content = input_api.ReadFile(primary_header_path, 'r')
4525 if include_re.search(content):
4526 continue
4527 except IOError:
4528 pass
4529 errors.append('%s:%d %s macro is used without including build/'
4530 'build_config.h.'
4531 % (f.LocalPath(), found_line_number, found_macro))
4532 if errors:
4533 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4534 return []
4535
4536
[email protected]b00342e7f2013-03-26 16:21:544537def _DidYouMeanOSMacro(bad_macro):
4538 try:
4539 return {'A': 'OS_ANDROID',
4540 'B': 'OS_BSD',
4541 'C': 'OS_CHROMEOS',
4542 'F': 'OS_FREEBSD',
4543 'L': 'OS_LINUX',
4544 'M': 'OS_MACOSX',
4545 'N': 'OS_NACL',
4546 'O': 'OS_OPENBSD',
4547 'P': 'OS_POSIX',
4548 'S': 'OS_SOLARIS',
4549 'W': 'OS_WIN'}[bad_macro[3].upper()]
4550 except KeyError:
4551 return ''
4552
4553
4554def _CheckForInvalidOSMacrosInFile(input_api, f):
4555 """Check for sensible looking, totally invalid OS macros."""
4556 preprocessor_statement = input_api.re.compile(r'^\s*#')
4557 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4558 results = []
4559 for lnum, line in f.ChangedContents():
4560 if preprocessor_statement.search(line):
4561 for match in os_macro.finditer(line):
4562 if not match.group(1) in _VALID_OS_MACROS:
4563 good = _DidYouMeanOSMacro(match.group(1))
4564 did_you_mean = ' (did you mean %s?)' % good if good else ''
4565 results.append(' %s:%d %s%s' % (f.LocalPath(),
4566 lnum,
4567 match.group(1),
4568 did_you_mean))
4569 return results
4570
4571
4572def _CheckForInvalidOSMacros(input_api, output_api):
4573 """Check all affected files for invalid OS macros."""
4574 bad_macros = []
tzik3f295992018-12-04 20:32:234575 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474576 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544577 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4578
4579 if not bad_macros:
4580 return []
4581
4582 return [output_api.PresubmitError(
4583 'Possibly invalid OS macro[s] found. Please fix your code\n'
4584 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4585
lliabraa35bab3932014-10-01 12:16:444586
4587def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4588 """Check all affected files for invalid "if defined" macros."""
4589 ALWAYS_DEFINED_MACROS = (
4590 "TARGET_CPU_PPC",
4591 "TARGET_CPU_PPC64",
4592 "TARGET_CPU_68K",
4593 "TARGET_CPU_X86",
4594 "TARGET_CPU_ARM",
4595 "TARGET_CPU_MIPS",
4596 "TARGET_CPU_SPARC",
4597 "TARGET_CPU_ALPHA",
4598 "TARGET_IPHONE_SIMULATOR",
4599 "TARGET_OS_EMBEDDED",
4600 "TARGET_OS_IPHONE",
4601 "TARGET_OS_MAC",
4602 "TARGET_OS_UNIX",
4603 "TARGET_OS_WIN32",
4604 )
4605 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4606 results = []
4607 for lnum, line in f.ChangedContents():
4608 for match in ifdef_macro.finditer(line):
4609 if match.group(1) in ALWAYS_DEFINED_MACROS:
4610 always_defined = ' %s is always defined. ' % match.group(1)
4611 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4612 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4613 lnum,
4614 always_defined,
4615 did_you_mean))
4616 return results
4617
4618
4619def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4620 """Check all affected files for invalid "if defined" macros."""
4621 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054622 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444623 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054624 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214625 continue
lliabraa35bab3932014-10-01 12:16:444626 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4627 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4628
4629 if not bad_macros:
4630 return []
4631
4632 return [output_api.PresubmitError(
4633 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4634 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4635 bad_macros)]
4636
4637
mlamouria82272622014-09-16 18:45:044638def _CheckForIPCRules(input_api, output_api):
4639 """Check for same IPC rules described in
4640 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4641 """
4642 base_pattern = r'IPC_ENUM_TRAITS\('
4643 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4644 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4645
4646 problems = []
4647 for f in input_api.AffectedSourceFiles(None):
4648 local_path = f.LocalPath()
4649 if not local_path.endswith('.h'):
4650 continue
4651 for line_number, line in f.ChangedContents():
4652 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4653 problems.append(
4654 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4655
4656 if problems:
4657 return [output_api.PresubmitPromptWarning(
4658 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4659 else:
4660 return []
4661
[email protected]b00342e7f2013-03-26 16:21:544662
Stephen Martinis97a394142018-06-07 23:06:054663def _CheckForLongPathnames(input_api, output_api):
4664 """Check to make sure no files being submitted have long paths.
4665 This causes issues on Windows.
4666 """
4667 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194668 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054669 local_path = f.LocalPath()
4670 # Windows has a path limit of 260 characters. Limit path length to 200 so
4671 # that we have some extra for the prefix on dev machines and the bots.
4672 if len(local_path) > 200:
4673 problems.append(local_path)
4674
4675 if problems:
4676 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4677 else:
4678 return []
4679
4680
Daniel Bratell8ba52722018-03-02 16:06:144681def _CheckForIncludeGuards(input_api, output_api):
4682 """Check that header files have proper guards against multiple inclusion.
4683 If a file should not have such guards (and it probably should) then it
4684 should include the string "no-include-guard-because-multiply-included".
4685 """
Daniel Bratell6a75baef62018-06-04 10:04:454686 def is_chromium_header_file(f):
4687 # We only check header files under the control of the Chromium
4688 # project. That is, those outside third_party apart from
4689 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324690 # We also exclude *_message_generator.h headers as they use
4691 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454692 file_with_path = input_api.os_path.normpath(f.LocalPath())
4693 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324694 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454695 (not file_with_path.startswith('third_party') or
4696 file_with_path.startswith(
4697 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144698
4699 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344700 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144701
4702 errors = []
4703
Daniel Bratell6a75baef62018-06-04 10:04:454704 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144705 guard_name = None
4706 guard_line_number = None
4707 seen_guard_end = False
4708
4709 file_with_path = input_api.os_path.normpath(f.LocalPath())
4710 base_file_name = input_api.os_path.splitext(
4711 input_api.os_path.basename(file_with_path))[0]
4712 upper_base_file_name = base_file_name.upper()
4713
4714 expected_guard = replace_special_with_underscore(
4715 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144716
4717 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574718 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4719 # are too many (1000+) files with slight deviations from the
4720 # coding style. The most important part is that the include guard
4721 # is there, and that it's unique, not the name so this check is
4722 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144723 #
4724 # As code becomes more uniform, this could be made stricter.
4725
4726 guard_name_pattern_list = [
4727 # Anything with the right suffix (maybe with an extra _).
4728 r'\w+_H__?',
4729
Daniel Bratell39b5b062018-05-16 18:09:574730 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144731 r'\w+_h',
4732
4733 # Anything including the uppercase name of the file.
4734 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4735 upper_base_file_name)) + r'\w*',
4736 ]
4737 guard_name_pattern = '|'.join(guard_name_pattern_list)
4738 guard_pattern = input_api.re.compile(
4739 r'#ifndef\s+(' + guard_name_pattern + ')')
4740
4741 for line_number, line in enumerate(f.NewContents()):
4742 if 'no-include-guard-because-multiply-included' in line:
4743 guard_name = 'DUMMY' # To not trigger check outside the loop.
4744 break
4745
4746 if guard_name is None:
4747 match = guard_pattern.match(line)
4748 if match:
4749 guard_name = match.group(1)
4750 guard_line_number = line_number
4751
Daniel Bratell39b5b062018-05-16 18:09:574752 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454753 # don't match the chromium style guide, but new files should
4754 # get it right.
4755 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574756 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144757 errors.append(output_api.PresubmitPromptWarning(
4758 'Header using the wrong include guard name %s' % guard_name,
4759 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574760 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144761 else:
4762 # The line after #ifndef should have a #define of the same name.
4763 if line_number == guard_line_number + 1:
4764 expected_line = '#define %s' % guard_name
4765 if line != expected_line:
4766 errors.append(output_api.PresubmitPromptWarning(
4767 'Missing "%s" for include guard' % expected_line,
4768 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4769 'Expected: %r\nGot: %r' % (expected_line, line)))
4770
4771 if not seen_guard_end and line == '#endif // %s' % guard_name:
4772 seen_guard_end = True
4773 elif seen_guard_end:
4774 if line.strip() != '':
4775 errors.append(output_api.PresubmitPromptWarning(
4776 'Include guard %s not covering the whole file' % (
4777 guard_name), [f.LocalPath()]))
4778 break # Nothing else to check and enough to warn once.
4779
4780 if guard_name is None:
4781 errors.append(output_api.PresubmitPromptWarning(
4782 'Missing include guard %s' % expected_guard,
4783 [f.LocalPath()],
4784 'Missing include guard in %s\n'
4785 'Recommended name: %s\n'
4786 'This check can be disabled by having the string\n'
4787 'no-include-guard-because-multiply-included in the header.' %
4788 (f.LocalPath(), expected_guard)))
4789
4790 return errors
4791
4792
mostynbb639aca52015-01-07 20:31:234793def _CheckForWindowsLineEndings(input_api, output_api):
4794 """Check source code and known ascii text files for Windows style line
4795 endings.
4796 """
earthdok1b5e0ee2015-03-10 15:19:104797 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234798
4799 file_inclusion_pattern = (
4800 known_text_files,
4801 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4802 )
4803
mostynbb639aca52015-01-07 20:31:234804 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534805 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444806 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534807 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504808 include_file = False
4809 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234810 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504811 include_file = True
4812 if include_file:
4813 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234814
4815 if problems:
4816 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4817 'these files to contain Windows style line endings?\n' +
4818 '\n'.join(problems))]
4819
4820 return []
4821
4822
Vaclav Brozekd5de76a2018-03-17 07:57:504823def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134824 """Checks that all source files use SYSLOG properly."""
4825 syslog_files = []
4826 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564827 for line_number, line in f.ChangedContents():
4828 if 'SYSLOG' in line:
4829 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4830
pastarmovj89f7ee12016-09-20 14:58:134831 if syslog_files:
4832 return [output_api.PresubmitPromptWarning(
4833 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4834 ' calls.\nFiles to check:\n', items=syslog_files)]
4835 return []
4836
4837
[email protected]1f7b4172010-01-28 01:17:344838def CheckChangeOnUpload(input_api, output_api):
4839 results = []
4840 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474841 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284842 results.extend(
jam93a6ee792017-02-08 23:59:224843 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194844 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224845 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134846 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164847 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534848 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194849 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274850 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544851 return results
[email protected]ca8d1982009-02-19 16:33:124852
4853
[email protected]1bfb8322014-04-23 01:02:414854def GetTryServerMasterForBot(bot):
4855 """Returns the Try Server master for the given bot.
4856
[email protected]0bb112362014-07-26 04:38:324857 It tries to guess the master from the bot name, but may still fail
4858 and return None. There is no longer a default master.
4859 """
4860 # Potentially ambiguous bot names are listed explicitly.
4861 master_map = {
tandriie5587792016-07-14 00:34:504862 'chromium_presubmit': 'master.tryserver.chromium.linux',
4863 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414864 }
[email protected]0bb112362014-07-26 04:38:324865 master = master_map.get(bot)
4866 if not master:
wnwen4fbaab82016-05-25 12:54:364867 if 'android' in bot:
tandriie5587792016-07-14 00:34:504868 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364869 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504870 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324871 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504872 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324873 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504874 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324875 return master
[email protected]1bfb8322014-04-23 01:02:414876
4877
[email protected]ca8d1982009-02-19 16:33:124878def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544879 results = []
[email protected]1f7b4172010-01-28 01:17:344880 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574881 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544882 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274883 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344884 input_api,
4885 output_api,
[email protected]2fdd1f362013-01-16 03:56:034886 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274887
jam93a6ee792017-02-08 23:59:224888 results.extend(
4889 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544890 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4891 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384892 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4893 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414894 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4895 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544896 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144897
4898
Rainhard Findlingfc31844c52020-05-15 09:58:264899def _CheckStrings(input_api, output_api):
4900 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024901 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4902 # footer is set to true.
4903 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264904 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024905 footer.lower()
4906 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264907 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024908
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144909 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264910 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144911 import sys
4912 from io import StringIO
4913
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144914 new_or_added_paths = set(f.LocalPath()
4915 for f in input_api.AffectedFiles()
4916 if (f.Action() == 'A' or f.Action() == 'M'))
4917 removed_paths = set(f.LocalPath()
4918 for f in input_api.AffectedFiles(include_deletes=True)
4919 if f.Action() == 'D')
4920
4921 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264922 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164923 if not affected_grds:
4924 return []
4925
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144926 affected_png_paths = [f.AbsoluteLocalPath()
4927 for f in input_api.AffectedFiles()
4928 if (f.LocalPath().endswith('.png'))]
4929
4930 # Check for screenshots. Developers can upload screenshots using
4931 # tools/translation/upload_screenshots.py which finds and uploads
4932 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4933 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4934 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4935 #
4936 # The logic here is as follows:
4937 #
4938 # - If the CL has a .png file under the screenshots directory for a grd
4939 # file, warn the developer. Actual images should never be checked into the
4940 # Chrome repo.
4941 #
4942 # - If the CL contains modified or new messages in grd files and doesn't
4943 # contain the corresponding .sha1 files, warn the developer to add images
4944 # and upload them via tools/translation/upload_screenshots.py.
4945 #
4946 # - If the CL contains modified or new messages in grd files and the
4947 # corresponding .sha1 files, everything looks good.
4948 #
4949 # - If the CL contains removed messages in grd files but the corresponding
4950 # .sha1 files aren't removed, warn the developer to remove them.
4951 unnecessary_screenshots = []
4952 missing_sha1 = []
4953 unnecessary_sha1_files = []
4954
Rainhard Findlingfc31844c52020-05-15 09:58:264955 # This checks verifies that the ICU syntax of messages this CL touched is
4956 # valid, and reports any found syntax errors.
4957 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4958 # without developers being aware of them. Later on, such ICU syntax errors
4959 # break message extraction for translation, hence would block Chromium
4960 # translations until they are fixed.
4961 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144962
4963 def _CheckScreenshotAdded(screenshots_dir, message_id):
4964 sha1_path = input_api.os_path.join(
4965 screenshots_dir, message_id + '.png.sha1')
4966 if sha1_path not in new_or_added_paths:
4967 missing_sha1.append(sha1_path)
4968
4969
4970 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4971 sha1_path = input_api.os_path.join(
4972 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034973 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144974 unnecessary_sha1_files.append(sha1_path)
4975
Rainhard Findlingfc31844c52020-05-15 09:58:264976
4977 def _ValidateIcuSyntax(text, level, signatures):
4978 """Validates ICU syntax of a text string.
4979
4980 Check if text looks similar to ICU and checks for ICU syntax correctness
4981 in this case. Reports various issues with ICU syntax and values of
4982 variants. Supports checking of nested messages. Accumulate information of
4983 each ICU messages found in the text for further checking.
4984
4985 Args:
4986 text: a string to check.
4987 level: a number of current nesting level.
4988 signatures: an accumulator, a list of tuple of (level, variable,
4989 kind, variants).
4990
4991 Returns:
4992 None if a string is not ICU or no issue detected.
4993 A tuple of (message, start index, end index) if an issue detected.
4994 """
4995 valid_types = {
4996 'plural': (frozenset(
4997 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4998 frozenset(['=1', 'other'])),
4999 'selectordinal': (frozenset(
5000 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5001 frozenset(['one', 'other'])),
5002 'select': (frozenset(), frozenset(['other'])),
5003 }
5004
5005 # Check if the message looks like an attempt to use ICU
5006 # plural. If yes - check if its syntax strictly matches ICU format.
5007 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5008 if not like:
5009 signatures.append((level, None, None, None))
5010 return
5011
5012 # Check for valid prefix and suffix
5013 m = re.match(
5014 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5015 r'(plural|selectordinal|select),\s*'
5016 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5017 if not m:
5018 return (('This message looks like an ICU plural, '
5019 'but does not follow ICU syntax.'), like.start(), like.end())
5020 starting, variable, kind, variant_pairs = m.groups()
5021 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5022 if depth:
5023 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5024 len(text))
5025 first = text[0]
5026 ending = text[last_pos:]
5027 if not starting:
5028 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5029 last_pos)
5030 if not ending or '}' not in ending:
5031 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5032 last_pos)
5033 elif first != '{':
5034 return (
5035 ('Invalid ICU format. Extra characters at the start of a complex '
5036 'message (go/icu-message-migration): "%s"') %
5037 starting, 0, len(starting))
5038 elif ending != '}':
5039 return (('Invalid ICU format. Extra characters at the end of a complex '
5040 'message (go/icu-message-migration): "%s"')
5041 % ending, last_pos - 1, len(text) - 1)
5042 if kind not in valid_types:
5043 return (('Unknown ICU message type %s. '
5044 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5045 known, required = valid_types[kind]
5046 defined_variants = set()
5047 for variant, variant_range, value, value_range in variants:
5048 start, end = variant_range
5049 if variant in defined_variants:
5050 return ('Variant "%s" is defined more than once' % variant,
5051 start, end)
5052 elif known and variant not in known:
5053 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5054 start, end)
5055 defined_variants.add(variant)
5056 # Check for nested structure
5057 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5058 if res:
5059 return (res[0], res[1] + value_range[0] + 1,
5060 res[2] + value_range[0] + 1)
5061 missing = required - defined_variants
5062 if missing:
5063 return ('Required variants missing: %s' % ', '.join(missing), 0,
5064 len(text))
5065 signatures.append((level, variable, kind, defined_variants))
5066
5067
5068 def _ParseIcuVariants(text, offset=0):
5069 """Parse variants part of ICU complex message.
5070
5071 Builds a tuple of variant names and values, as well as
5072 their offsets in the input string.
5073
5074 Args:
5075 text: a string to parse
5076 offset: additional offset to add to positions in the text to get correct
5077 position in the complete ICU string.
5078
5079 Returns:
5080 List of tuples, each tuple consist of four fields: variant name,
5081 variant name span (tuple of two integers), variant value, value
5082 span (tuple of two integers).
5083 """
5084 depth, start, end = 0, -1, -1
5085 variants = []
5086 key = None
5087 for idx, char in enumerate(text):
5088 if char == '{':
5089 if not depth:
5090 start = idx
5091 chunk = text[end + 1:start]
5092 key = chunk.strip()
5093 pos = offset + end + 1 + chunk.find(key)
5094 span = (pos, pos + len(key))
5095 depth += 1
5096 elif char == '}':
5097 if not depth:
5098 return variants, depth, offset + idx
5099 depth -= 1
5100 if not depth:
5101 end = idx
5102 variants.append((key, span, text[start:end + 1], (offset + start,
5103 offset + end + 1)))
5104 return variants, depth, offset + end + 1
5105
meacer8c0d3832019-12-26 21:46:165106 try:
5107 old_sys_path = sys.path
5108 sys.path = sys.path + [input_api.os_path.join(
5109 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5110 from helper import grd_helper
5111 finally:
5112 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145113
5114 for f in affected_grds:
5115 file_path = f.LocalPath()
5116 old_id_to_msg_map = {}
5117 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385118 # Note that this code doesn't check if the file has been deleted. This is
5119 # OK because it only uses the old and new file contents and doesn't load
5120 # the file via its path.
5121 # It's also possible that a file's content refers to a renamed or deleted
5122 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5123 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5124 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145125 if file_path.endswith('.grdp'):
5126 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585127 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395128 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585130 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395131 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132 else:
meacerff8a9b62019-12-10 19:43:585133 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585135 old_id_to_msg_map = grd_helper.GetGrdMessages(
5136 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585138 new_id_to_msg_map = grd_helper.GetGrdMessages(
5139 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
5141 # Compute added, removed and modified message IDs.
5142 old_ids = set(old_id_to_msg_map)
5143 new_ids = set(new_id_to_msg_map)
5144 added_ids = new_ids - old_ids
5145 removed_ids = old_ids - new_ids
5146 modified_ids = set([])
5147 for key in old_ids.intersection(new_ids):
5148 if (old_id_to_msg_map[key].FormatXml()
5149 != new_id_to_msg_map[key].FormatXml()):
5150 modified_ids.add(key)
5151
5152 grd_name, ext = input_api.os_path.splitext(
5153 input_api.os_path.basename(file_path))
5154 screenshots_dir = input_api.os_path.join(
5155 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5156
Rainhard Findlingfc31844c52020-05-15 09:58:265157 if run_screenshot_check:
5158 # Check the screenshot directory for .png files. Warn if there is any.
5159 for png_path in affected_png_paths:
5160 if png_path.startswith(screenshots_dir):
5161 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145162
Rainhard Findlingfc31844c52020-05-15 09:58:265163 for added_id in added_ids:
5164 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145165
Rainhard Findlingfc31844c52020-05-15 09:58:265166 for modified_id in modified_ids:
5167 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145168
Rainhard Findlingfc31844c52020-05-15 09:58:265169 for removed_id in removed_ids:
5170 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5171
5172 # Check new and changed strings for ICU syntax errors.
5173 for key in added_ids.union(modified_ids):
5174 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5175 err = _ValidateIcuSyntax(msg, 0, [])
5176 if err is not None:
5177 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145178
5179 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265180 if run_screenshot_check:
5181 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005182 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265183 'Do not include actual screenshots in the changelist. Run '
5184 'tools/translate/upload_screenshots.py to upload them instead:',
5185 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145186
Rainhard Findlingfc31844c52020-05-15 09:58:265187 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005188 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265189 'You are adding or modifying UI strings.\n'
5190 'To ensure the best translations, take screenshots of the relevant UI '
5191 '(https://g.co/chrome/translation) and add these files to your '
5192 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145193
Rainhard Findlingfc31844c52020-05-15 09:58:265194 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005195 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265196 'You removed strings associated with these files. Remove:',
5197 sorted(unnecessary_sha1_files)))
5198 else:
5199 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5200 'screenshots check.'))
5201
5202 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075203 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265204 'ICU syntax errors were found in the following strings (problems or '
5205 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145206
5207 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125208
5209
5210def _CheckTranslationExpectations(input_api, output_api,
5211 repo_root=None,
5212 translation_expectations_path=None,
5213 grd_files=None):
5214 import sys
5215 affected_grds = [f for f in input_api.AffectedFiles()
5216 if (f.LocalPath().endswith('.grd') or
5217 f.LocalPath().endswith('.grdp'))]
5218 if not affected_grds:
5219 return []
5220
5221 try:
5222 old_sys_path = sys.path
5223 sys.path = sys.path + [
5224 input_api.os_path.join(
5225 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5226 from helper import git_helper
5227 from helper import translation_helper
5228 finally:
5229 sys.path = old_sys_path
5230
5231 # Check that translation expectations can be parsed and we can get a list of
5232 # translatable grd files. |repo_root| and |translation_expectations_path| are
5233 # only passed by tests.
5234 if not repo_root:
5235 repo_root = input_api.PresubmitLocalPath()
5236 if not translation_expectations_path:
5237 translation_expectations_path = input_api.os_path.join(
5238 repo_root, 'tools', 'gritsettings',
5239 'translation_expectations.pyl')
5240 if not grd_files:
5241 grd_files = git_helper.list_grds_in_repository(repo_root)
5242
5243 try:
5244 translation_helper.get_translatable_grds(repo_root, grd_files,
5245 translation_expectations_path)
5246 except Exception as e:
5247 return [output_api.PresubmitNotifyResult(
5248 'Failed to get a list of translatable grd files. This happens when:\n'
5249 ' - One of the modified grd or grdp files cannot be parsed or\n'
5250 ' - %s is not updated.\n'
5251 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5252 return []
Ken Rockotc31f4832020-05-29 18:58:515253
5254
5255def _CheckStableMojomChanges(input_api, output_api):
5256 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095257 changed_mojoms = input_api.AffectedFiles(
5258 include_deletes=True,
5259 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515260 delta = []
5261 for mojom in changed_mojoms:
5262 old_contents = ''.join(mojom.OldContents()) or None
5263 new_contents = ''.join(mojom.NewContents()) or None
5264 delta.append({
5265 'filename': mojom.LocalPath(),
5266 'old': '\n'.join(mojom.OldContents()) or None,
5267 'new': '\n'.join(mojom.NewContents()) or None,
5268 })
5269
5270 process = input_api.subprocess.Popen(
5271 [input_api.python_executable,
5272 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5273 'public', 'tools', 'mojom',
5274 'check_stable_mojom_compatibility.py'),
5275 '--src-root', input_api.PresubmitLocalPath()],
5276 stdin=input_api.subprocess.PIPE,
5277 stdout=input_api.subprocess.PIPE,
5278 stderr=input_api.subprocess.PIPE,
5279 universal_newlines=True)
5280 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5281 if process.returncode:
5282 return [output_api.PresubmitError(
5283 'One or more [Stable] mojom definitions appears to have been changed '
5284 'in a way that is not backward-compatible.',
5285 long_text=error)]
5286 return []