blob: dbd77dcea1fd937a2f874e41447a6163ac3d4f99 [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 = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
28 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
29 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1430 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5432 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4034)
[email protected]ca8d1982009-02-19 16:33:1235
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Fragment of a regular expression that matches C++ and Objective-C++
38# implementation files.
39_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40
wnwenbdc444e2016-05-25 13:44:1541
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1942# Fragment of a regular expression that matches C++ and Objective-C++
43# header files.
44_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
45
46
[email protected]06e6d0ff2012-12-11 01:36:4447# Regular expression that matches code only used for test binaries
48# (best effort).
49_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0450 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4452 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1253 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1854 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4455 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0456 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0557 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0458 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4759 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0460 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0861 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0462 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4463)
[email protected]ca8d1982009-02-19 16:33:1264
Daniel Bratell609102be2019-03-27 20:53:2165_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1566
[email protected]eea609a2011-11-18 13:10:1267_TEST_ONLY_WARNING = (
68 'You might be calling functions intended only for testing from\n'
69 'production code. It is OK to ignore this warning if you know what\n'
70 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5871 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1272
73
[email protected]cf9b78f2012-11-14 11:40:2874_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4075 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2176 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
77 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2878
wnwenbdc444e2016-05-25 13:44:1579
Daniel Bratell609102be2019-03-27 20:53:2180# Format: Sequence of tuples containing:
81# * String pattern or, if starting with a slash, a regular expression.
82# * Sequence of strings to show when the pattern matches.
83# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4184_BANNED_JAVA_FUNCTIONS = (
85 (
86 'StrictMode.allowThreadDiskReads()',
87 (
88 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
89 'directly.',
90 ),
91 False,
92 ),
93 (
94 'StrictMode.allowThreadDiskWrites()',
95 (
96 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
97 'directly.',
98 ),
99 False,
100 ),
101)
102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59107_BANNED_OBJC_FUNCTIONS = (
108 (
109 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20110 (
111 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59112 'prohibited. Please use CrTrackingArea instead.',
113 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
114 ),
115 False,
116 ),
117 (
[email protected]eaae1972014-04-16 04:17:26118 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20119 (
120 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59121 'instead.',
122 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
123 ),
124 False,
125 ),
126 (
127 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20128 (
129 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59130 'Please use |convertPoint:(point) fromView:nil| instead.',
131 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
132 ),
133 True,
134 ),
135 (
136 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20137 (
138 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59139 'Please use |convertPoint:(point) toView:nil| instead.',
140 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 ),
142 True,
143 ),
144 (
145 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20146 (
147 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59148 'Please use |convertRect:(point) fromView:nil| instead.',
149 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
150 ),
151 True,
152 ),
153 (
154 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59157 'Please use |convertRect:(point) toView:nil| instead.',
158 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
159 ),
160 True,
161 ),
162 (
163 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20164 (
165 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59166 'Please use |convertSize:(point) fromView:nil| instead.',
167 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
168 ),
169 True,
170 ),
171 (
172 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20173 (
174 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59175 'Please use |convertSize:(point) toView:nil| instead.',
176 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
177 ),
178 True,
179 ),
jif65398702016-10-27 10:19:48180 (
181 r"/\s+UTF8String\s*]",
182 (
183 'The use of -[NSString UTF8String] is dangerous as it can return null',
184 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
185 'Please use |SysNSStringToUTF8| instead.',
186 ),
187 True,
188 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34189 (
190 r'__unsafe_unretained',
191 (
192 'The use of __unsafe_unretained is almost certainly wrong, unless',
193 'when interacting with NSFastEnumeration or NSInvocation.',
194 'Please use __weak in files build with ARC, nothing otherwise.',
195 ),
196 False,
197 ),
Avi Drissman7382afa02019-04-29 23:27:13198 (
199 'freeWhenDone:NO',
200 (
201 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
202 'Foundation types is prohibited.',
203 ),
204 True,
205 ),
[email protected]127f18ec2012-06-16 05:05:59206)
207
Daniel Bratell609102be2019-03-27 20:53:21208# Format: Sequence of tuples containing:
209# * String pattern or, if starting with a slash, a regular expression.
210# * Sequence of strings to show when the pattern matches.
211# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54212_BANNED_IOS_OBJC_FUNCTIONS = (
213 (
214 r'/\bTEST[(]',
215 (
216 'TEST() macro should not be used in Objective-C++ code as it does not ',
217 'drain the autorelease pool at the end of the test. Use TEST_F() ',
218 'macro instead with a fixture inheriting from PlatformTest (or a ',
219 'typedef).'
220 ),
221 True,
222 ),
223 (
224 r'/\btesting::Test\b',
225 (
226 'testing::Test should not be used in Objective-C++ code as it does ',
227 'not drain the autorelease pool at the end of the test. Use ',
228 'PlatformTest instead.'
229 ),
230 True,
231 ),
232)
233
Peter K. Lee6c03ccff2019-07-15 14:40:05234# 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.
238_BANNED_IOS_EGTEST_FUNCTIONS = (
239 (
240 r'/\bEXPECT_OCMOCK_VERIFY\b',
241 (
242 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
243 'it is meant for GTests. Use [mock verify] instead.'
244 ),
245 True,
246 ),
247)
248
danakj7a2b7082019-05-21 21:13:51249# Directories that contain deprecated Bind() or Callback types.
250# Find sub-directories from a given directory by running:
251# for i in `find . -maxdepth 1 -type d`; do
252# echo "-- $i"
253# (cd $i; git grep -P 'base::(Bind\(|(Callback<|Closure))'|wc -l)
254# done
255#
256# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
257# when they have been converted to modern callback types (OnceCallback,
258# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
259# checks for them and prevent regressions.
260_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
261 '^android_webview/browser/',
262 '^apps/',
263 '^ash/',
danakj7a2b7082019-05-21 21:13:51264 '^base/callback.h', # Intentional.
265 '^chrome/app/',
266 '^chrome/browser/',
267 '^chrome/chrome_elf/',
268 '^chrome/chrome_watcher/',
269 '^chrome/common/',
270 '^chrome/installer/',
271 '^chrome/notification_helper/',
272 '^chrome/renderer/',
273 '^chrome/services/',
274 '^chrome/test/',
275 '^chrome/tools/',
276 '^chrome/utility/',
277 '^chromecast/app/',
278 '^chromecast/browser/',
279 '^chromecast/crash/',
280 '^chromecast/media/',
281 '^chromecast/metrics/',
282 '^chromecast/net/',
283 '^chromeos/attestation/',
284 '^chromeos/audio/',
285 '^chromeos/components/',
286 '^chromeos/cryptohome/',
287 '^chromeos/dbus/',
288 '^chromeos/geolocation/',
289 '^chromeos/login/',
290 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51291 '^chromeos/process_proxy/',
292 '^chromeos/services/',
293 '^chromeos/settings/',
294 '^chromeos/timezone/',
295 '^chromeos/tpm/',
296 '^components/arc/',
297 '^components/assist_ranker/',
298 '^components/autofill/',
299 '^components/autofill_assistant/',
300 '^components/bookmarks/',
301 '^components/browser_sync/',
302 '^components/browser_watcher/',
303 '^components/browsing_data/',
304 '^components/cast_channel/',
305 '^components/certificate_transparency/',
306 '^components/chromeos_camera/',
307 '^components/component_updater/',
308 '^components/content_settings/',
309 '^components/crash/',
310 '^components/cronet/',
311 '^components/data_reduction_proxy/',
312 '^components/discardable_memory/',
313 '^components/dom_distiller/',
314 '^components/domain_reliability/',
315 '^components/download/',
316 '^components/drive/',
317 '^components/exo/',
318 '^components/favicon/',
319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
323 '^components/google/',
324 '^components/guest_view/',
325 '^components/heap_profiling/',
326 '^components/history/',
327 '^components/image_fetcher/',
328 '^components/invalidation/',
329 '^components/keyed_service/',
330 '^components/login/',
331 '^components/metrics/',
332 '^components/metrics_services_manager/',
333 '^components/nacl/',
334 '^components/navigation_interception/',
335 '^components/net_log/',
336 '^components/network_time/',
337 '^components/ntp_snippets/',
338 '^components/ntp_tiles/',
339 '^components/offline_items_collection/',
340 '^components/offline_pages/',
341 '^components/omnibox/',
342 '^components/ownership/',
343 '^components/pairing/',
344 '^components/password_manager/',
345 '^components/payments/',
346 '^components/plugins/',
347 '^components/policy/',
348 '^components/pref_registry/',
349 '^components/prefs/',
danakj7a2b7082019-05-21 21:13:51350 '^components/proxy_config/',
351 '^components/quirks/',
352 '^components/rappor/',
353 '^components/remote_cocoa/',
354 '^components/renderer_context_menu/',
355 '^components/rlz/',
356 '^components/safe_browsing/',
357 '^components/search_engines/',
358 '^components/search_provider_logos/',
359 '^components/security_interstitials/',
360 '^components/security_state/',
361 '^components/services/',
362 '^components/sessions/',
363 '^components/signin/',
364 '^components/ssl_errors/',
365 '^components/storage_monitor/',
366 '^components/subresource_filter/',
367 '^components/suggestions/',
368 '^components/supervised_user_error_page/',
369 '^components/sync/',
370 '^components/sync_bookmarks/',
371 '^components/sync_device_info/',
372 '^components/sync_preferences/',
373 '^components/sync_sessions/',
374 '^components/test/',
375 '^components/tracing/',
376 '^components/translate/',
377 '^components/ukm/',
378 '^components/update_client/',
379 '^components/upload_list/',
380 '^components/variations/',
381 '^components/visitedlink/',
382 '^components/web_cache/',
383 '^components/web_resource/',
danakj7a2b7082019-05-21 21:13:51384 '^components/webcrypto/',
385 '^components/webdata/',
386 '^components/webdata_services/',
387 '^components/wifi/',
388 '^components/zoom/',
389 '^content/app/',
390 '^content/browser/',
391 '^content/child/',
392 '^content/common/',
393 '^content/public/',
394 '^content/renderer/android/',
395 '^content/renderer/fetchers/',
396 '^content/renderer/image_downloader/',
397 '^content/renderer/input/',
398 '^content/renderer/java/',
399 '^content/renderer/media/',
400 '^content/renderer/media_capture_from_element/',
401 '^content/renderer/media_recorder/',
402 '^content/renderer/p2p/',
403 '^content/renderer/pepper/',
404 '^content/renderer/service_worker/',
405 '^content/renderer/worker/',
406 '^content/test/',
407 '^content/utility/',
408 '^dbus/',
409 '^device/base/',
410 '^device/bluetooth/',
411 '^device/fido/',
412 '^device/gamepad/',
413 '^device/udev_linux/',
414 '^device/vr/',
415 '^extensions/',
416 '^gin/',
417 '^google_apis/dive/',
418 '^google_apis/gaia/',
419 '^google_apis/gcm/',
420 '^headless/',
421 '^ios/chrome/',
422 '^ios/components/',
423 '^ios/net/',
424 '^ios/web/',
425 '^ios/web_view/',
426 '^ipc/',
427 '^media/audio/',
428 '^media/base/',
429 '^media/capture/',
430 '^media/cast/',
431 '^media/cdm/',
432 '^media/device_monitors/',
433 '^media/ffmpeg/',
434 '^media/filters/',
435 '^media/formats/',
436 '^media/gpu/',
437 '^media/mojo/',
438 '^media/muxers/',
439 '^media/remoting/',
440 '^media/renderers/',
441 '^media/test/',
442 '^mojo/core/',
443 '^mojo/public/',
444 '^net/',
445 '^ppapi/proxy/',
446 '^ppapi/shared_impl/',
447 '^ppapi/tests/',
448 '^ppapi/thunk/',
449 '^remoting/base/',
450 '^remoting/client/',
451 '^remoting/codec/',
452 '^remoting/host/',
453 '^remoting/internal/',
454 '^remoting/ios/',
455 '^remoting/protocol/',
456 '^remoting/signaling/',
457 '^remoting/test/',
458 '^sandbox/linux/',
459 '^sandbox/win/',
460 '^services/',
461 '^storage/browser/',
462 '^testing/gmock_mutant.h',
463 '^testing/libfuzzer/',
464 '^third_party/blink/',
465 '^third_party/crashpad/crashpad/test/gtest_main.cc',
466 '^third_party/leveldatabase/leveldb_chrome.cc',
467 '^third_party/boringssl/gtest_main_chromium.cc',
468 '^third_party/cacheinvalidation/overrides/' +
469 'google/cacheinvalidation/deps/callback.h',
470 '^third_party/libaddressinput/chromium/chrome_address_validator.cc',
471 '^third_party/zlib/google/',
472 '^tools/android/',
473 '^tools/clang/base_bind_rewriters/', # Intentional.
474 '^tools/gdb/gdb_chrome.py', # Intentional.
475 '^ui/accelerated_widget_mac/',
476 '^ui/android/',
477 '^ui/aura/',
478 '^ui/base/',
479 '^ui/compositor/',
480 '^ui/display/',
481 '^ui/events/',
482 '^ui/gfx/',
483 '^ui/message_center/',
danakj7a2b7082019-05-21 21:13:51484 '^ui/snapshot/',
485 '^ui/views_content_client/',
486 '^ui/wm/',
487))
[email protected]127f18ec2012-06-16 05:05:59488
Daniel Bratell609102be2019-03-27 20:53:21489# Format: Sequence of tuples containing:
490# * String pattern or, if starting with a slash, a regular expression.
491# * Sequence of strings to show when the pattern matches.
492# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
493# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59494_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20495 (
Dave Tapuska98199b612019-07-10 13:30:44496 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53497 (
498 'New code should not use NULL. Use nullptr instead.',
499 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20500 False,
thomasandersone7caaa9b2017-03-29 19:22:53501 (),
502 ),
Antonio Gomes07300d02019-03-13 20:59:57503 # Make sure that gtest's FRIEND_TEST() macro is not used; the
504 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
505 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53506 (
[email protected]23e6cbc2012-06-16 18:51:20507 'FRIEND_TEST(',
508 (
[email protected]e3c945502012-06-26 20:01:49509 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20510 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
511 ),
512 False,
[email protected]7345da02012-11-27 14:31:49513 (),
[email protected]23e6cbc2012-06-16 18:51:20514 ),
515 (
Dave Tapuska98199b612019-07-10 13:30:44516 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53517 (
518 'Chrome clients wishing to select events on X windows should use',
519 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
520 'you are selecting events from the GPU process, or if you are using',
521 'an XDisplay other than gfx::GetXDisplay().',
522 ),
523 True,
524 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40525 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04526 r"^ui[\\/]gl[\\/].*\.cc$",
527 r"^media[\\/]gpu[\\/].*\.cc$",
528 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53529 ),
530 ),
531 (
Dave Tapuska98199b612019-07-10 13:30:44532 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20533 (
thomasanderson11aa41d2017-06-08 22:22:38534 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20535 ),
536 True,
537 (
Egor Paskoce145c42018-09-28 19:31:04538 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
539 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
540 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20541 ),
542 ),
543 (
tomhudsone2c14d552016-05-26 17:07:46544 'setMatrixClip',
545 (
546 'Overriding setMatrixClip() is prohibited; ',
547 'the base function is deprecated. ',
548 ),
549 True,
550 (),
551 ),
552 (
[email protected]52657f62013-05-20 05:30:31553 'SkRefPtr',
554 (
555 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22556 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31557 ),
558 True,
559 (),
560 ),
561 (
562 'SkAutoRef',
563 (
564 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22565 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31566 ),
567 True,
568 (),
569 ),
570 (
571 'SkAutoTUnref',
572 (
573 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22574 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31575 ),
576 True,
577 (),
578 ),
579 (
580 'SkAutoUnref',
581 (
582 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
583 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22584 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31585 ),
586 True,
587 (),
588 ),
[email protected]d89eec82013-12-03 14:10:59589 (
590 r'/HANDLE_EINTR\(.*close',
591 (
592 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
593 'descriptor will be closed, and it is incorrect to retry the close.',
594 'Either call close directly and ignore its return value, or wrap close',
595 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
596 ),
597 True,
598 (),
599 ),
600 (
601 r'/IGNORE_EINTR\((?!.*close)',
602 (
603 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
604 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
605 ),
606 True,
607 (
608 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04609 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
610 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59611 ),
612 ),
[email protected]ec5b3f02014-04-04 18:43:43613 (
614 r'/v8::Extension\(',
615 (
616 'Do not introduce new v8::Extensions into the code base, use',
617 'gin::Wrappable instead. See http://crbug.com/334679',
618 ),
619 True,
[email protected]f55c90ee62014-04-12 00:50:03620 (
Egor Paskoce145c42018-09-28 19:31:04621 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03622 ),
[email protected]ec5b3f02014-04-04 18:43:43623 ),
skyostilf9469f72015-04-20 10:38:52624 (
jame2d1a952016-04-02 00:27:10625 '#pragma comment(lib,',
626 (
627 'Specify libraries to link with in build files and not in the source.',
628 ),
629 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41630 (
tzik3f295992018-12-04 20:32:23631 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04632 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41633 ),
jame2d1a952016-04-02 00:27:10634 ),
fdorayc4ac18d2017-05-01 21:39:59635 (
Gabriel Charette7cc6c432018-04-25 20:52:02636 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59637 (
638 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
639 ),
640 False,
641 (),
642 ),
643 (
Gabriel Charette7cc6c432018-04-25 20:52:02644 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59645 (
646 'Consider using THREAD_CHECKER macros instead of the class directly.',
647 ),
648 False,
649 (),
650 ),
dbeamb6f4fde2017-06-15 04:03:06651 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06652 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
653 (
654 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
655 'deprecated (http://crbug.com/634507). Please avoid converting away',
656 'from the Time types in Chromium code, especially if any math is',
657 'being done on time values. For interfacing with platform/library',
658 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
659 'type converter methods instead. For faking TimeXXX values (for unit',
660 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
661 'other use cases, please contact base/time/OWNERS.',
662 ),
663 False,
664 (),
665 ),
666 (
dbeamb6f4fde2017-06-15 04:03:06667 'CallJavascriptFunctionUnsafe',
668 (
669 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
670 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
671 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
672 ),
673 False,
674 (
Egor Paskoce145c42018-09-28 19:31:04675 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
676 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
677 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06678 ),
679 ),
dskiba1474c2bfd62017-07-20 02:19:24680 (
681 'leveldb::DB::Open',
682 (
683 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
684 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
685 "Chrome's tracing, making their memory usage visible.",
686 ),
687 True,
688 (
689 r'^third_party/leveldatabase/.*\.(cc|h)$',
690 ),
Gabriel Charette0592c3a2017-07-26 12:02:04691 ),
692 (
Chris Mumfordc38afb62017-10-09 17:55:08693 'leveldb::NewMemEnv',
694 (
695 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58696 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
697 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08698 ),
699 True,
700 (
701 r'^third_party/leveldatabase/.*\.(cc|h)$',
702 ),
703 ),
704 (
Gabriel Charetted9839bc2017-07-29 14:17:47705 'RunLoop::QuitCurrent',
706 (
Robert Liao64b7ab22017-08-04 23:03:43707 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
708 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47709 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41710 False,
Gabriel Charetted9839bc2017-07-29 14:17:47711 (),
Gabriel Charettea44975052017-08-21 23:14:04712 ),
713 (
714 'base::ScopedMockTimeMessageLoopTaskRunner',
715 (
Gabriel Charette87cc1af2018-04-25 20:52:51716 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11717 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51718 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
719 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
720 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04721 ),
Gabriel Charette87cc1af2018-04-25 20:52:51722 False,
Gabriel Charettea44975052017-08-21 23:14:04723 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57724 ),
725 (
Dave Tapuska98199b612019-07-10 13:30:44726 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57727 (
728 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02729 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57730 ),
731 True,
732 (),
Francois Doray43670e32017-09-27 12:40:38733 ),
734 (
Peter Kasting991618a62019-06-17 22:00:09735 r'/\bstd::stoi\b',
736 (
737 'std::stoi uses exceptions to communicate results. ',
738 'Use base::StringToInt() instead.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
742 ),
743 (
744 r'/\bstd::stol\b',
745 (
746 'std::stol uses exceptions to communicate results. ',
747 'Use base::StringToInt() instead.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
751 ),
752 (
753 r'/\bstd::stoul\b',
754 (
755 'std::stoul uses exceptions to communicate results. ',
756 'Use base::StringToUint() instead.',
757 ),
758 True,
759 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
760 ),
761 (
762 r'/\bstd::stoll\b',
763 (
764 'std::stoll uses exceptions to communicate results. ',
765 'Use base::StringToInt64() instead.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
769 ),
770 (
771 r'/\bstd::stoull\b',
772 (
773 'std::stoull uses exceptions to communicate results. ',
774 'Use base::StringToUint64() instead.',
775 ),
776 True,
777 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
778 ),
779 (
780 r'/\bstd::stof\b',
781 (
782 'std::stof uses exceptions to communicate results. ',
783 'For locale-independent values, e.g. reading numbers from disk',
784 'profiles, use base::StringToDouble().',
785 'For user-visible values, parse using ICU.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
789 ),
790 (
791 r'/\bstd::stod\b',
792 (
793 'std::stod uses exceptions to communicate results. ',
794 'For locale-independent values, e.g. reading numbers from disk',
795 'profiles, use base::StringToDouble().',
796 'For user-visible values, parse using ICU.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
800 ),
801 (
802 r'/\bstd::stold\b',
803 (
804 'std::stold uses exceptions to communicate results. ',
805 'For locale-independent values, e.g. reading numbers from disk',
806 'profiles, use base::StringToDouble().',
807 'For user-visible values, parse using ICU.',
808 ),
809 True,
810 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
811 ),
812 (
Daniel Bratell69334cc2019-03-26 11:07:45813 r'/\bstd::to_string\b',
814 (
815 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09816 'For locale-independent strings, e.g. writing numbers to disk',
817 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45818 'For user-visible strings, use base::FormatNumber() and',
819 'the related functions in base/i18n/number_formatting.h.',
820 ),
Peter Kasting991618a62019-06-17 22:00:09821 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21822 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45823 ),
824 (
825 r'/\bstd::shared_ptr\b',
826 (
827 'std::shared_ptr should not be used. Use scoped_refptr instead.',
828 ),
829 True,
Daniel Bratell609102be2019-03-27 20:53:21830 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
831 ),
832 (
Peter Kasting991618a62019-06-17 22:00:09833 r'/\bstd::weak_ptr\b',
834 (
835 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
836 ),
837 True,
838 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
839 ),
840 (
Daniel Bratell609102be2019-03-27 20:53:21841 r'/\blong long\b',
842 (
843 'long long is banned. Use stdint.h if you need a 64 bit number.',
844 ),
845 False, # Only a warning since it is already used.
846 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
847 ),
848 (
849 r'/\bstd::bind\b',
850 (
851 'std::bind is banned because of lifetime risks.',
852 'Use base::BindOnce or base::BindRepeating instead.',
853 ),
854 True,
855 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
856 ),
857 (
858 r'/\b#include <chrono>\b',
859 (
860 '<chrono> overlaps with Time APIs in base. Keep using',
861 'base classes.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
865 ),
866 (
867 r'/\b#include <exception>\b',
868 (
869 'Exceptions are banned and disabled in Chromium.',
870 ),
871 True,
872 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
873 ),
874 (
875 r'/\bstd::function\b',
876 (
877 'std::function is banned. Instead use base::Callback which directly',
878 'supports Chromium\'s weak pointers, ref counting and more.',
879 ),
Peter Kasting991618a62019-06-17 22:00:09880 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21881 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
882 ),
883 (
884 r'/\b#include <random>\b',
885 (
886 'Do not use any random number engines from <random>. Instead',
887 'use base::RandomBitGenerator.',
888 ),
889 True,
890 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
891 ),
892 (
893 r'/\bstd::ratio\b',
894 (
895 'std::ratio is banned by the Google Style Guide.',
896 ),
897 True,
898 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45899 ),
900 (
Francois Doray43670e32017-09-27 12:40:38901 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
902 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
903 (
904 'Use the new API in base/threading/thread_restrictions.h.',
905 ),
Gabriel Charette04b138f2018-08-06 00:03:22906 False,
Francois Doray43670e32017-09-27 12:40:38907 (),
908 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38909 (
danakj7a2b7082019-05-21 21:13:51910 r'/\bbase::Bind\(',
911 (
912 'Please use base::Bind{Once,Repeating} instead',
913 'of base::Bind. (crbug.com/714018)',
914 ),
915 False,
916 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
917 ),
918 (
919 r'/\bbase::Callback[<:]',
920 (
921 'Please use base::{Once,Repeating}Callback instead',
922 'of base::Callback. (crbug.com/714018)',
923 ),
924 False,
925 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
926 ),
927 (
928 r'/\bbase::Closure\b',
929 (
930 'Please use base::{Once,Repeating}Closure instead',
931 'of base::Closure. (crbug.com/714018)',
932 ),
933 False,
934 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
935 ),
936 (
Alex Ilin5929abe32019-04-03 17:09:34937 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45938 (
939 'base::SharedMemory is deprecated. Please use',
940 '{Writable,ReadOnly}SharedMemoryRegion instead.',
941 ),
942 False,
943 (),
944 ),
945 (
Michael Giuffrida7f93d6922019-04-19 14:39:58946 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19947 (
948 'RunMessageLoop is deprecated, use RunLoop instead.',
949 ),
950 False,
951 (),
952 ),
953 (
Dave Tapuska98199b612019-07-10 13:30:44954 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19955 (
956 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
957 ),
958 False,
959 (),
960 ),
961 (
Dave Tapuska98199b612019-07-10 13:30:44962 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19963 (
964 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
965 "if you're convinced you need this.",
966 ),
967 False,
968 (),
969 ),
970 (
Dave Tapuska98199b612019-07-10 13:30:44971 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19972 (
973 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04974 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19975 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
976 'async events instead of flushing threads.',
977 ),
978 False,
979 (),
980 ),
981 (
982 r'MessageLoopRunner',
983 (
984 'MessageLoopRunner is deprecated, use RunLoop instead.',
985 ),
986 False,
987 (),
988 ),
989 (
Dave Tapuska98199b612019-07-10 13:30:44990 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19991 (
992 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
993 "gab@ if you found a use case where this is the only solution.",
994 ),
995 False,
996 (),
997 ),
998 (
Victor Costane48a2e82019-03-15 22:02:34999 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161000 (
Victor Costane48a2e82019-03-15 22:02:341001 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161002 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1003 ),
1004 True,
1005 (
1006 r'^sql/initialization\.(cc|h)$',
1007 r'^third_party/sqlite/.*\.(c|cc|h)$',
1008 ),
1009 ),
Matt Menke7f520a82018-03-28 21:38:371010 (
1011 'net::URLFetcher',
1012 (
1013 'net::URLFetcher should no longer be used in content embedders. ',
1014 'Instead, use network::SimpleURLLoader instead, which supports ',
1015 'an out-of-process network stack. ',
1016 'net::URLFetcher may still be used in binaries that do not embed',
1017 'content.',
1018 ),
Matt Menke59716d02018-04-05 12:45:531019 False,
Matt Menke7f520a82018-03-28 21:38:371020 (
Egor Paskoce145c42018-09-28 19:31:041021 r'^ios[\\/].*\.(cc|h)$',
1022 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:371023 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:041024 r'^net[\\/].*\.(cc|h)$',
1025 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Fabrice de Gans-Riberi9345311c2019-08-30 23:33:431026 r'^fuchsia/base/test_devtools_list_fetcher\.cc$',
Matt Menke7f520a82018-03-28 21:38:371027 ),
1028 ),
jdoerried7d10ab2018-04-27 10:46:131029 (
Dave Tapuska98199b612019-07-10 13:30:441030 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471031 (
1032 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1033 'base::RandomShuffle instead.'
1034 ),
1035 True,
1036 (),
1037 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241038 (
1039 'ios/web/public/test/http_server',
1040 (
1041 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1042 ),
1043 False,
1044 (),
1045 ),
Robert Liao764c9492019-01-24 18:46:281046 (
1047 'GetAddressOf',
1048 (
1049 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1050 'implicated in a few leaks. Use operator& instead.'
1051 ),
1052 True,
1053 (),
1054 ),
Antonio Gomes07300d02019-03-13 20:59:571055 (
1056 'DEFINE_TYPE_CASTS',
1057 (
1058 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
1059 '//third_party/blink/renderer/platform/casting.h.'
1060 ),
1061 True,
1062 (
1063 r'^third_party/blink/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381066 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371067 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381068 (
1069 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1070 ),
1071 True,
1072 (),
1073 ),
Ben Lewisa9514602019-04-29 17:53:051074 (
1075 'SHFileOperation',
1076 (
1077 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1078 'complex functions to achieve the same goals. Use IFileOperation for ',
1079 'any esoteric actions instead.'
1080 ),
1081 True,
1082 (),
1083 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181084 (
Cliff Smolinsky81951642019-04-30 21:39:511085 'StringFromGUID2',
1086 (
1087 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1088 'Use base::win::String16FromGUID instead.'
1089 ),
1090 True,
1091 (
1092 r'/base/win/win_util_unittest.cc'
1093 ),
1094 ),
1095 (
1096 'StringFromCLSID',
1097 (
1098 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1099 'Use base::win::String16FromGUID instead.'
1100 ),
1101 True,
1102 (
1103 r'/base/win/win_util_unittest.cc'
1104 ),
1105 ),
1106 (
Avi Drissman7382afa02019-04-29 23:27:131107 'kCFAllocatorNull',
1108 (
1109 'The use of kCFAllocatorNull with the NoCopy creation of ',
1110 'CoreFoundation types is prohibited.',
1111 ),
1112 True,
1113 (),
1114 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291115 (
1116 'mojo::ConvertTo',
1117 (
1118 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1119 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1120 'StringTraits if you would like to convert between custom types and',
1121 'the wire format of mojom types.'
1122 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221123 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291124 (
Wezf89dec092019-09-11 19:38:331125 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1126 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291127 r'^third_party/blink/.*\.(cc|h)$',
1128 r'^content/renderer/.*\.(cc|h)$',
1129 ),
1130 ),
[email protected]127f18ec2012-06-16 05:05:591131)
1132
Mario Sanchez Prada2472cab2019-09-18 10:58:311133# Format: Sequence of tuples containing:
1134# * String pattern or, if starting with a slash, a regular expression.
1135# * Sequence of strings to show when the pattern matches.
1136_DEPRECATED_MOJO_TYPES = (
1137 (
1138 r'/\bmojo::AssociatedBinding\b',
1139 (
1140 'mojo::AssociatedBinding<Interface> is deprecated.',
1141 'Use mojo::AssociatedReceiver<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::AssociatedBindingSet\b',
1146 (
1147 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1148 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::AssociatedInterfacePtr\b',
1153 (
1154 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1155 'Use mojo::AssociatedRemote<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1160 (
1161 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1162 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::AssociatedInterfaceRequest\b',
1167 (
1168 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1169 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::Binding\b',
1174 (
1175 'mojo::Binding<Interface> is deprecated.',
1176 'Use mojo::Receiver<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::BindingSet\b',
1181 (
1182 'mojo::BindingSet<Interface> is deprecated.',
1183 'Use mojo::ReceiverSet<Interface> instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::InterfacePtr\b',
1188 (
1189 'mojo::InterfacePtr<Interface> is deprecated.',
1190 'Use mojo::Remote<Interface> instead.',
1191 ),
1192 ),
1193 (
1194 r'/\bmojo::InterfacePtrInfo\b',
1195 (
1196 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1197 'Use mojo::PendingRemote<Interface> instead.',
1198 ),
1199 ),
1200 (
1201 r'/\bmojo::InterfaceRequest\b',
1202 (
1203 'mojo::InterfaceRequest<Interface> is deprecated.',
1204 'Use mojo::PendingReceiver<Interface> instead.',
1205 ),
1206 ),
1207 (
1208 r'/\bmojo::MakeRequest\b',
1209 (
1210 'mojo::MakeRequest is deprecated.',
1211 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1212 ),
1213 ),
1214 (
1215 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1216 (
1217 'mojo::MakeRequest is deprecated.',
1218 'Use mojo::AssociatedRemote::'
1219 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1220 ),
1221 ),
1222 (
1223 r'/\bmojo::MakeStrongBinding\b',
1224 (
1225 'mojo::MakeStrongBinding is deprecated.',
1226 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1227 'mojo::MakeSelfOwnedReceiver() instead.',
1228 ),
1229 ),
1230 (
1231 r'/\bmojo::MakeStrongAssociatedBinding\b',
1232 (
1233 'mojo::MakeStrongAssociatedBinding is deprecated.',
1234 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1235 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1236 ),
1237 ),
1238 (
1239 r'/\bmojo::StrongAssociatedBindingSet\b',
1240 (
1241 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1242 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1243 ),
1244 ),
1245 (
1246 r'/\bmojo::StrongBindingSet\b',
1247 (
1248 'mojo::StrongBindingSet<Interface> is deprecated.',
1249 'Use mojo::UniqueReceiverSet<Interface> instead.',
1250 ),
1251 ),
1252)
wnwenbdc444e2016-05-25 13:44:151253
mlamouria82272622014-09-16 18:45:041254_IPC_ENUM_TRAITS_DEPRECATED = (
1255 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501256 'See http://www.chromium.org/Home/chromium-security/education/'
1257 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041258
Stephen Martinis97a394142018-06-07 23:06:051259_LONG_PATH_ERROR = (
1260 'Some files included in this CL have file names that are too long (> 200'
1261 ' characters). If committed, these files will cause issues on Windows. See'
1262 ' https://crbug.com/612667 for more details.'
1263)
1264
Shenghua Zhangbfaa38b82017-11-16 21:58:021265_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041266 r".*[\\/]BuildHooksAndroidImpl\.java",
1267 r".*[\\/]LicenseContentProvider\.java",
1268 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281269 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021270]
[email protected]127f18ec2012-06-16 05:05:591271
Sean Kau46e29bc2017-08-28 16:31:161272# These paths contain test data and other known invalid JSON files.
1273_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041274 r'test[\\/]data[\\/]',
1275 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1276 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041277 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431278 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161279]
1280
1281
[email protected]b00342e7f2013-03-26 16:21:541282_VALID_OS_MACROS = (
1283 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081284 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121286 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_BSD',
1288 'OS_CAT', # For testing.
1289 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041290 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371292 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541293 'OS_IOS',
1294 'OS_LINUX',
1295 'OS_MACOSX',
1296 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211297 'OS_NACL_NONSFI',
1298 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121299 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541300 'OS_OPENBSD',
1301 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371302 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541303 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541304 'OS_WIN',
1305)
1306
1307
agrievef32bcc72016-04-04 14:57:401308_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391309 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361310 'base/android/jni_generator/jni_generator.pydeps',
1311 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221312 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/android/gyp/aar.pydeps',
1314 'build/android/gyp/aidl.pydeps',
1315 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381316 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/bytecode_processor.pydeps',
1318 'build/android/gyp/compile_resources.pydeps',
Tibor Goldschwendt84ec04c2019-08-23 21:19:091319 'build/android/gyp/create_app_bundle_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1321 'build/android/gyp/copy_ex.pydeps',
1322 'build/android/gyp/create_app_bundle.pydeps',
1323 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221325 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/create_tool_wrapper.pydeps',
1327 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591328 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/dex.pydeps',
1330 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361331 'build/android/gyp/filter_zip.pydeps',
1332 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361333 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581335 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261337 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/javac.pydeps',
1339 'build/android/gyp/jinja_template.pydeps',
1340 'build/android/gyp/lint.pydeps',
1341 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/merge_manifest.pydeps',
1343 'build/android/gyp/prepare_resources.pydeps',
1344 'build/android/gyp/proguard.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241345 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461347 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561348 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/incremental_install/generate_android_manifest.pydeps',
1350 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221351 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401352 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041353 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411355 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:191356 'net/tools/testserver/testserver.pydeps',
Andrew Luo338fe6e82019-09-19 07:17:431357 'testing/scripts/run_android_wpt.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021358 'third_party/android_platform/development/scripts/stack.pydeps',
John Budorick207963292019-09-13 16:53:321359 'tools/android/avd/avd.pydeps',
agrievef32bcc72016-04-04 14:57:401360]
1361
wnwenbdc444e2016-05-25 13:44:151362
agrievef32bcc72016-04-04 14:57:401363_GENERIC_PYDEPS_FILES = [
anthonyvd7323c982019-09-11 14:36:421364 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131365 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421366 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1367 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131368 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061369 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221370 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401371]
1372
wnwenbdc444e2016-05-25 13:44:151373
agrievef32bcc72016-04-04 14:57:401374_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1375
1376
Eric Boren6fd2b932018-01-25 15:05:081377# Bypass the AUTHORS check for these accounts.
1378_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:291379 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
1380 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:081381 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:321382 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:591383 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451384 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591385 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:221386 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041387 ) | set('%[email protected]' % s
1388 for s in ('chromium-autoroll',)
1389 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301390 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081391
1392
Daniel Bratell65b033262019-04-23 08:17:061393def _IsCPlusPlusFile(input_api, file_path):
1394 """Returns True if this file contains C++-like code (and not Python,
1395 Go, Java, MarkDown, ...)"""
1396
1397 ext = input_api.os_path.splitext(file_path)[1]
1398 # This list is compatible with CppChecker.IsCppFile but we should
1399 # consider adding ".c" to it. If we do that we can use this function
1400 # at more places in the code.
1401 return ext in (
1402 '.h',
1403 '.cc',
1404 '.cpp',
1405 '.m',
1406 '.mm',
1407 )
1408
1409def _IsCPlusPlusHeaderFile(input_api, file_path):
1410 return input_api.os_path.splitext(file_path)[1] == ".h"
1411
1412
1413def _IsJavaFile(input_api, file_path):
1414 return input_api.os_path.splitext(file_path)[1] == ".java"
1415
1416
1417def _IsProtoFile(input_api, file_path):
1418 return input_api.os_path.splitext(file_path)[1] == ".proto"
1419
[email protected]55459852011-08-10 15:17:191420def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1421 """Attempts to prevent use of functions intended only for testing in
1422 non-testing code. For now this is just a best-effort implementation
1423 that ignores header files and may have some false positives. A
1424 better implementation would probably need a proper C++ parser.
1425 """
1426 # We only scan .cc files and the like, as the declaration of
1427 # for-testing functions in header files are hard to distinguish from
1428 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491429 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191430
jochenc0d4808c2015-07-27 09:25:421431 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191432 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091433 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191434 exclusion_pattern = input_api.re.compile(
1435 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1436 base_function_pattern, base_function_pattern))
1437
1438 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441439 black_list = (_EXCLUDED_PATHS +
1440 _TEST_CODE_EXCLUDED_PATHS +
1441 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191442 return input_api.FilterSourceFile(
1443 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491444 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191445 black_list=black_list)
1446
1447 problems = []
1448 for f in input_api.AffectedSourceFiles(FilterFile):
1449 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241450 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031451 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461452 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031453 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191454 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031455 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191456
1457 if problems:
[email protected]f7051d52013-04-02 18:31:421458 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031459 else:
1460 return []
[email protected]55459852011-08-10 15:17:191461
1462
Vaclav Brozek7dbc28c2018-03-27 08:35:231463def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1464 """This is a simplified version of
1465 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1466 """
1467 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1468 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1469 name_pattern = r'ForTest(s|ing)?'
1470 # Describes an occurrence of "ForTest*" inside a // comment.
1471 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1472 # Catch calls.
1473 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1474 # Ignore definitions. (Comments are ignored separately.)
1475 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1476
1477 problems = []
1478 sources = lambda x: input_api.FilterSourceFile(
1479 x,
1480 black_list=(('(?i).*test', r'.*\/junit\/')
1481 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491482 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231483 )
1484 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1485 local_path = f.LocalPath()
1486 is_inside_javadoc = False
1487 for line_number, line in f.ChangedContents():
1488 if is_inside_javadoc and javadoc_end_re.search(line):
1489 is_inside_javadoc = False
1490 if not is_inside_javadoc and javadoc_start_re.search(line):
1491 is_inside_javadoc = True
1492 if is_inside_javadoc:
1493 continue
1494 if (inclusion_re.search(line) and
1495 not comment_re.search(line) and
1496 not exclusion_re.search(line)):
1497 problems.append(
1498 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1499
1500 if problems:
1501 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1502 else:
1503 return []
1504
1505
[email protected]10689ca2011-09-02 02:31:541506def _CheckNoIOStreamInHeaders(input_api, output_api):
1507 """Checks to make sure no .h files include <iostream>."""
1508 files = []
1509 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1510 input_api.re.MULTILINE)
1511 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1512 if not f.LocalPath().endswith('.h'):
1513 continue
1514 contents = input_api.ReadFile(f)
1515 if pattern.search(contents):
1516 files.append(f)
1517
1518 if len(files):
yolandyandaabc6d2016-04-18 18:29:391519 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061520 'Do not #include <iostream> in header files, since it inserts static '
1521 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541522 '#include <ostream>. See http://crbug.com/94794',
1523 files) ]
1524 return []
1525
Danil Chapovalov3518f362018-08-11 16:13:431526def _CheckNoStrCatRedefines(input_api, output_api):
1527 """Checks no windows headers with StrCat redefined are included directly."""
1528 files = []
1529 pattern_deny = input_api.re.compile(
1530 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1531 input_api.re.MULTILINE)
1532 pattern_allow = input_api.re.compile(
1533 r'^#include\s"base/win/windows_defines.inc"',
1534 input_api.re.MULTILINE)
1535 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1536 contents = input_api.ReadFile(f)
1537 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1538 files.append(f.LocalPath())
1539
1540 if len(files):
1541 return [output_api.PresubmitError(
1542 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1543 'directly since they pollute code with StrCat macro. Instead, '
1544 'include matching header from base/win. See http://crbug.com/856536',
1545 files) ]
1546 return []
1547
[email protected]10689ca2011-09-02 02:31:541548
[email protected]72df4e782012-06-21 16:28:181549def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521550 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181551 problems = []
1552 for f in input_api.AffectedFiles():
1553 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1554 continue
1555
1556 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041557 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181558 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1559
1560 if not problems:
1561 return []
1562 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1563 '\n'.join(problems))]
1564
Dominic Battre033531052018-09-24 15:45:341565def _CheckNoDISABLETypoInTests(input_api, output_api):
1566 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1567
1568 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1569 instead of DISABLED_. To filter false positives, reports are only generated
1570 if a corresponding MAYBE_ line exists.
1571 """
1572 problems = []
1573
1574 # The following two patterns are looked for in tandem - is a test labeled
1575 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1576 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1577 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1578
1579 # This is for the case that a test is disabled on all platforms.
1580 full_disable_pattern = input_api.re.compile(
1581 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1582 input_api.re.MULTILINE)
1583
Katie Df13948e2018-09-25 07:33:441584 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341585 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1586 continue
1587
1588 # Search for MABYE_, DISABLE_ pairs.
1589 disable_lines = {} # Maps of test name to line number.
1590 maybe_lines = {}
1591 for line_num, line in f.ChangedContents():
1592 disable_match = disable_pattern.search(line)
1593 if disable_match:
1594 disable_lines[disable_match.group(1)] = line_num
1595 maybe_match = maybe_pattern.search(line)
1596 if maybe_match:
1597 maybe_lines[maybe_match.group(1)] = line_num
1598
1599 # Search for DISABLE_ occurrences within a TEST() macro.
1600 disable_tests = set(disable_lines.keys())
1601 maybe_tests = set(maybe_lines.keys())
1602 for test in disable_tests.intersection(maybe_tests):
1603 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1604
1605 contents = input_api.ReadFile(f)
1606 full_disable_match = full_disable_pattern.search(contents)
1607 if full_disable_match:
1608 problems.append(' %s' % f.LocalPath())
1609
1610 if not problems:
1611 return []
1612 return [
1613 output_api.PresubmitPromptWarning(
1614 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1615 '\n'.join(problems))
1616 ]
1617
[email protected]72df4e782012-06-21 16:28:181618
danakj61c1aa22015-10-26 19:55:521619def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571620 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521621 errors = []
1622 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1623 input_api.re.MULTILINE)
1624 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1625 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1626 continue
1627 for lnum, line in f.ChangedContents():
1628 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171629 errors.append(output_api.PresubmitError(
1630 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571631 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171632 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521633 return errors
1634
1635
Makoto Shimazu3ad422cd2019-05-08 02:35:141636def _FindHistogramNameInChunk(histogram_name, chunk):
1637 """Tries to find a histogram name or prefix in a line.
1638
1639 Returns the existence of the histogram name, or None if it needs more chunk
1640 to determine."""
mcasasb7440c282015-02-04 14:52:191641 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1642 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141643 if '<affected-histogram' in chunk:
1644 # If the tag is not completed, needs more chunk to get the name.
1645 if not '>' in chunk:
1646 return None
1647 if not 'name="' in chunk:
1648 return False
1649 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1650 # expect the only attribute is the name.
1651 histogram_prefix = chunk.split('"')[1]
1652 return histogram_prefix in histogram_name
1653 # Typically the whole histogram name should in the line.
1654 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191655
1656
1657def _CheckUmaHistogramChanges(input_api, output_api):
1658 """Check that UMA histogram names in touched lines can still be found in other
1659 lines of the patch or in histograms.xml. Note that this check would not catch
1660 the reverse: changes in histograms.xml not matched in the code itself."""
1661 touched_histograms = []
1662 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471663 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1664 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1665 name_pattern = r'"(.*?)"'
1666 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1667 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1668 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1669 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1670 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171671 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191672 for f in input_api.AffectedFiles():
1673 # If histograms.xml itself is modified, keep the modified lines for later.
1674 if f.LocalPath().endswith(('histograms.xml')):
1675 histograms_xml_modifications = f.ChangedContents()
1676 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471677 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1678 single_line_re = single_line_c_re
1679 split_line_prefix_re = split_line_c_prefix_re
1680 elif f.LocalPath().endswith(('java')):
1681 single_line_re = single_line_java_re
1682 split_line_prefix_re = split_line_java_prefix_re
1683 else:
mcasasb7440c282015-02-04 14:52:191684 continue
1685 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171686 if last_line_matched_prefix:
1687 suffix_found = split_line_suffix_re.search(line)
1688 if suffix_found :
1689 touched_histograms.append([suffix_found.group(1), f, line_num])
1690 last_line_matched_prefix = False
1691 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061692 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191693 if found:
1694 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171695 continue
1696 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191697
1698 # Search for the touched histogram names in the local modifications to
1699 # histograms.xml, and, if not found, on the base histograms.xml file.
1700 unmatched_histograms = []
1701 for histogram_info in touched_histograms:
1702 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141703 chunk = ''
mcasasb7440c282015-02-04 14:52:191704 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141705 chunk += line
1706 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1707 if histogram_name_found is None:
1708 continue
1709 chunk = ''
mcasasb7440c282015-02-04 14:52:191710 if histogram_name_found:
1711 break
1712 if not histogram_name_found:
1713 unmatched_histograms.append(histogram_info)
1714
eromanb90c82e7e32015-04-01 15:13:491715 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191716 problems = []
1717 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491718 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191719 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451720 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191721 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141722 chunk = ''
mcasasb7440c282015-02-04 14:52:191723 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141724 chunk += line
1725 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1726 chunk)
1727 if histogram_name_found is None:
1728 continue
1729 chunk = ''
mcasasb7440c282015-02-04 14:52:191730 if histogram_name_found:
1731 break
1732 if not histogram_name_found:
1733 problems.append(' [%s:%d] %s' %
1734 (f.LocalPath(), line_num, histogram_name))
1735
1736 if not problems:
1737 return []
1738 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1739 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491740 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191741
wnwenbdc444e2016-05-25 13:44:151742
yolandyandaabc6d2016-04-18 18:29:391743def _CheckFlakyTestUsage(input_api, output_api):
1744 """Check that FlakyTest annotation is our own instead of the android one"""
1745 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1746 files = []
1747 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1748 if f.LocalPath().endswith('Test.java'):
1749 if pattern.search(input_api.ReadFile(f)):
1750 files.append(f)
1751 if len(files):
1752 return [output_api.PresubmitError(
1753 'Use org.chromium.base.test.util.FlakyTest instead of '
1754 'android.test.FlakyTest',
1755 files)]
1756 return []
mcasasb7440c282015-02-04 14:52:191757
wnwenbdc444e2016-05-25 13:44:151758
[email protected]8ea5d4b2011-09-13 21:49:221759def _CheckNoNewWStrings(input_api, output_api):
1760 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271761 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221762 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201763 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571764 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341765 '/win/' in f.LocalPath() or
1766 'chrome_elf' in f.LocalPath() or
1767 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201768 continue
[email protected]8ea5d4b2011-09-13 21:49:221769
[email protected]a11dbe9b2012-08-07 01:32:581770 allowWString = False
[email protected]b5c24292011-11-28 14:38:201771 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581772 if 'presubmit: allow wstring' in line:
1773 allowWString = True
1774 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271775 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581776 allowWString = False
1777 else:
1778 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221779
[email protected]55463aa62011-10-12 00:48:271780 if not problems:
1781 return []
1782 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581783 ' If you are calling a cross-platform API that accepts a wstring, '
1784 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271785 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221786
1787
[email protected]2a8ac9c2011-10-19 17:20:441788def _CheckNoDEPSGIT(input_api, output_api):
1789 """Make sure .DEPS.git is never modified manually."""
1790 if any(f.LocalPath().endswith('.DEPS.git') for f in
1791 input_api.AffectedFiles()):
1792 return [output_api.PresubmitError(
1793 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1794 'automated system based on what\'s in DEPS and your changes will be\n'
1795 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501796 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1797 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441798 'for more information')]
1799 return []
1800
1801
tandriief664692014-09-23 14:51:471802def _CheckValidHostsInDEPS(input_api, output_api):
1803 """Checks that DEPS file deps are from allowed_hosts."""
1804 # Run only if DEPS file has been modified to annoy fewer bystanders.
1805 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1806 return []
1807 # Outsource work to gclient verify
1808 try:
John Budorickf20c0042019-04-25 23:23:401809 gclient_path = input_api.os_path.join(
1810 input_api.PresubmitLocalPath(),
1811 'third_party', 'depot_tools', 'gclient.py')
1812 input_api.subprocess.check_output(
1813 [input_api.python_executable, gclient_path, 'verify'],
1814 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471815 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201816 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471817 return [output_api.PresubmitError(
1818 'DEPS file must have only git dependencies.',
1819 long_text=error.output)]
1820
1821
Mario Sanchez Prada2472cab2019-09-18 10:58:311822def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1823 type_name, message):
1824 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1825
1826 Returns an string composed of the name of the file, the line number where the
1827 match has been found and the additional text passed as |message| in case the
1828 target type name matches the text inside the line passed as parameter.
1829 """
1830 matched = False
1831 if type_name[0:1] == '/':
1832 regex = type_name[1:]
1833 if input_api.re.search(regex, line):
1834 matched = True
1835 elif type_name in line:
1836 matched = True
1837
1838 result = []
1839 if matched:
1840 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1841 for message_line in message:
1842 result.append(' %s' % message_line)
1843
1844 return result
1845
1846
[email protected]127f18ec2012-06-16 05:05:591847def _CheckNoBannedFunctions(input_api, output_api):
1848 """Make sure that banned functions are not used."""
1849 warnings = []
1850 errors = []
1851
wnwenbdc444e2016-05-25 13:44:151852 def IsBlacklisted(affected_file, blacklist):
1853 local_path = affected_file.LocalPath()
1854 for item in blacklist:
1855 if input_api.re.match(item, local_path):
1856 return True
1857 return False
1858
Peter K. Lee6c03ccff2019-07-15 14:40:051859 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541860 local_path = affected_file.LocalPath()
1861 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1862 return False
1863 basename = input_api.os_path.basename(local_path)
1864 if 'ios' in basename.split('_'):
1865 return True
1866 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1867 if sep and 'ios' in local_path.split(sep):
1868 return True
1869 return False
1870
wnwenbdc444e2016-05-25 13:44:151871 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311872 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1873 func_name, message)
1874 if problems:
wnwenbdc444e2016-05-25 13:44:151875 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311876 errors.extend(problems)
1877 else:
1878 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151879
Eric Stevensona9a980972017-09-23 00:04:411880 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1881 for f in input_api.AffectedFiles(file_filter=file_filter):
1882 for line_num, line in f.ChangedContents():
1883 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1884 CheckForMatch(f, line_num, line, func_name, message, error)
1885
[email protected]127f18ec2012-06-16 05:05:591886 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1887 for f in input_api.AffectedFiles(file_filter=file_filter):
1888 for line_num, line in f.ChangedContents():
1889 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151890 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591891
Peter K. Lee6c03ccff2019-07-15 14:40:051892 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541893 for line_num, line in f.ChangedContents():
1894 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1895 CheckForMatch(f, line_num, line, func_name, message, error)
1896
Peter K. Lee6c03ccff2019-07-15 14:40:051897 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1898 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1899 for line_num, line in f.ChangedContents():
1900 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1901 CheckForMatch(f, line_num, line, func_name, message, error)
1902
[email protected]127f18ec2012-06-16 05:05:591903 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1904 for f in input_api.AffectedFiles(file_filter=file_filter):
1905 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491906 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491907 if IsBlacklisted(f, excluded_paths):
1908 continue
wnwenbdc444e2016-05-25 13:44:151909 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591910
1911 result = []
1912 if (warnings):
1913 result.append(output_api.PresubmitPromptWarning(
1914 'Banned functions were used.\n' + '\n'.join(warnings)))
1915 if (errors):
1916 result.append(output_api.PresubmitError(
1917 'Banned functions were used.\n' + '\n'.join(errors)))
1918 return result
1919
1920
Mario Sanchez Prada2472cab2019-09-18 10:58:311921def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1922 """Make sure that old Mojo types are not used."""
1923 warnings = []
1924
1925 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1926 for f in input_api.AffectedFiles(file_filter=file_filter):
1927 # Only need to check Blink for warnings for now.
1928 if not f.LocalPath().startswith('third_party/blink'):
1929 continue
1930
1931 for line_num, line in f.ChangedContents():
1932 for func_name, message in _DEPRECATED_MOJO_TYPES:
1933 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1934 func_name, message)
1935 if problems:
1936 warnings.extend(problems)
1937
1938 result = []
1939 if (warnings):
1940 result.append(output_api.PresubmitPromptWarning(
1941 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
1942 return result
1943
1944
[email protected]6c063c62012-07-11 19:11:061945def _CheckNoPragmaOnce(input_api, output_api):
1946 """Make sure that banned functions are not used."""
1947 files = []
1948 pattern = input_api.re.compile(r'^#pragma\s+once',
1949 input_api.re.MULTILINE)
1950 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1951 if not f.LocalPath().endswith('.h'):
1952 continue
1953 contents = input_api.ReadFile(f)
1954 if pattern.search(contents):
1955 files.append(f)
1956
1957 if files:
1958 return [output_api.PresubmitError(
1959 'Do not use #pragma once in header files.\n'
1960 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1961 files)]
1962 return []
1963
[email protected]127f18ec2012-06-16 05:05:591964
[email protected]e7479052012-09-19 00:26:121965def _CheckNoTrinaryTrueFalse(input_api, output_api):
1966 """Checks to make sure we don't introduce use of foo ? true : false."""
1967 problems = []
1968 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1969 for f in input_api.AffectedFiles():
1970 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1971 continue
1972
1973 for line_num, line in f.ChangedContents():
1974 if pattern.match(line):
1975 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1976
1977 if not problems:
1978 return []
1979 return [output_api.PresubmitPromptWarning(
1980 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1981 '\n'.join(problems))]
1982
1983
[email protected]55f9f382012-07-31 11:02:181984def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281985 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181986 change. Breaking - rules is an error, breaking ! rules is a
1987 warning.
1988 """
mohan.reddyf21db962014-10-16 12:26:471989 import sys
[email protected]55f9f382012-07-31 11:02:181990 # We need to wait until we have an input_api object and use this
1991 # roundabout construct to import checkdeps because this file is
1992 # eval-ed and thus doesn't have __file__.
1993 original_sys_path = sys.path
1994 try:
1995 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471996 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181997 import checkdeps
[email protected]55f9f382012-07-31 11:02:181998 from rules import Rule
1999 finally:
2000 # Restore sys.path to what it was before.
2001 sys.path = original_sys_path
2002
2003 added_includes = []
rhalavati08acd232017-04-03 07:23:282004 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242005 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182006 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062007 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502008 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082009 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062010 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502011 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082012 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062013 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502014 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082015 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182016
[email protected]26385172013-05-09 23:11:352017 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182018
2019 error_descriptions = []
2020 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282021 error_subjects = set()
2022 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182023 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2024 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082025 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182026 description_with_path = '%s\n %s' % (path, rule_description)
2027 if rule_type == Rule.DISALLOW:
2028 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282029 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182030 else:
2031 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282032 warning_subjects.add("#includes")
2033
2034 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2035 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082036 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282037 description_with_path = '%s\n %s' % (path, rule_description)
2038 if rule_type == Rule.DISALLOW:
2039 error_descriptions.append(description_with_path)
2040 error_subjects.add("imports")
2041 else:
2042 warning_descriptions.append(description_with_path)
2043 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182044
Jinsuk Kim5a092672017-10-24 22:42:242045 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022046 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082047 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242048 description_with_path = '%s\n %s' % (path, rule_description)
2049 if rule_type == Rule.DISALLOW:
2050 error_descriptions.append(description_with_path)
2051 error_subjects.add("imports")
2052 else:
2053 warning_descriptions.append(description_with_path)
2054 warning_subjects.add("imports")
2055
[email protected]55f9f382012-07-31 11:02:182056 results = []
2057 if error_descriptions:
2058 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282059 'You added one or more %s that violate checkdeps rules.'
2060 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182061 error_descriptions))
2062 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422063 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282064 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182065 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282066 '%s? See relevant DEPS file(s) for details and contacts.' %
2067 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182068 warning_descriptions))
2069 return results
2070
2071
[email protected]fbcafe5a2012-08-08 15:31:222072def _CheckFilePermissions(input_api, output_api):
2073 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152074 if input_api.platform == 'win32':
2075 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292076 checkperms_tool = input_api.os_path.join(
2077 input_api.PresubmitLocalPath(),
2078 'tools', 'checkperms', 'checkperms.py')
2079 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472080 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392081 with input_api.CreateTemporaryFile() as file_list:
2082 for f in input_api.AffectedFiles():
2083 # checkperms.py file/directory arguments must be relative to the
2084 # repository.
2085 file_list.write(f.LocalPath() + '\n')
2086 file_list.close()
2087 args += ['--file-list', file_list.name]
2088 try:
2089 input_api.subprocess.check_output(args)
2090 return []
2091 except input_api.subprocess.CalledProcessError as error:
2092 return [output_api.PresubmitError(
2093 'checkperms.py failed:',
2094 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222095
2096
robertocn832f5992017-01-04 19:01:302097def _CheckTeamTags(input_api, output_api):
2098 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2099 checkteamtags_tool = input_api.os_path.join(
2100 input_api.PresubmitLocalPath(),
2101 'tools', 'checkteamtags', 'checkteamtags.py')
2102 args = [input_api.python_executable, checkteamtags_tool,
2103 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222104 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302105 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2106 'OWNERS']
2107 try:
2108 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052109 warnings = input_api.subprocess.check_output(args + files).splitlines()
2110 if warnings:
2111 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302112 return []
2113 except input_api.subprocess.CalledProcessError as error:
2114 return [output_api.PresubmitError(
2115 'checkteamtags.py failed:',
2116 long_text=error.output)]
2117
2118
[email protected]c8278b32012-10-30 20:35:492119def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2120 """Makes sure we don't include ui/aura/window_property.h
2121 in header files.
2122 """
2123 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2124 errors = []
2125 for f in input_api.AffectedFiles():
2126 if not f.LocalPath().endswith('.h'):
2127 continue
2128 for line_num, line in f.ChangedContents():
2129 if pattern.match(line):
2130 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2131
2132 results = []
2133 if errors:
2134 results.append(output_api.PresubmitError(
2135 'Header files should not include ui/aura/window_property.h', errors))
2136 return results
2137
2138
[email protected]70ca77752012-11-20 03:45:032139def _CheckForVersionControlConflictsInFile(input_api, f):
2140 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2141 errors = []
2142 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162143 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232144 # First-level headers in markdown look a lot like version control
2145 # conflict markers. http://daringfireball.net/projects/markdown/basics
2146 continue
[email protected]70ca77752012-11-20 03:45:032147 if pattern.match(line):
2148 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2149 return errors
2150
2151
2152def _CheckForVersionControlConflicts(input_api, output_api):
2153 """Usually this is not intentional and will cause a compile failure."""
2154 errors = []
2155 for f in input_api.AffectedFiles():
2156 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2157
2158 results = []
2159 if errors:
2160 results.append(output_api.PresubmitError(
2161 'Version control conflict markers found, please resolve.', errors))
2162 return results
2163
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202164
estadee17314a02017-01-12 16:22:162165def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2166 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2167 errors = []
2168 for f in input_api.AffectedFiles():
2169 for line_num, line in f.ChangedContents():
2170 if pattern.search(line):
2171 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2172
2173 results = []
2174 if errors:
2175 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502176 'Found Google support URL addressed by answer number. Please replace '
2177 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162178 return results
2179
[email protected]70ca77752012-11-20 03:45:032180
[email protected]06e6d0ff2012-12-11 01:36:442181def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2182 def FilterFile(affected_file):
2183 """Filter function for use with input_api.AffectedSourceFiles,
2184 below. This filters out everything except non-test files from
2185 top-level directories that generally speaking should not hard-code
2186 service URLs (e.g. src/android_webview/, src/content/ and others).
2187 """
2188 return input_api.FilterSourceFile(
2189 affected_file,
Egor Paskoce145c42018-09-28 19:31:042190 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442191 black_list=(_EXCLUDED_PATHS +
2192 _TEST_CODE_EXCLUDED_PATHS +
2193 input_api.DEFAULT_BLACK_LIST))
2194
reillyi38965732015-11-16 18:27:332195 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2196 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462197 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2198 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442199 problems = [] # items are (filename, line_number, line)
2200 for f in input_api.AffectedSourceFiles(FilterFile):
2201 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462202 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442203 problems.append((f.LocalPath(), line_num, line))
2204
2205 if problems:
[email protected]f7051d52013-04-02 18:31:422206 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442207 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582208 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442209 [' %s:%d: %s' % (
2210 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032211 else:
2212 return []
[email protected]06e6d0ff2012-12-11 01:36:442213
2214
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492215# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272216def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2217 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312218 The native_client_sdk directory is excluded because it has auto-generated PNG
2219 files for documentation.
[email protected]d2530012013-01-25 16:39:272220 """
[email protected]d2530012013-01-25 16:39:272221 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492222 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042223 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312224 file_filter = lambda f: input_api.FilterSourceFile(
2225 f, white_list=white_list, black_list=black_list)
2226 for f in input_api.AffectedFiles(include_deletes=False,
2227 file_filter=file_filter):
2228 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272229
2230 results = []
2231 if errors:
2232 results.append(output_api.PresubmitError(
2233 'The name of PNG files should not have abbreviations. \n'
2234 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2235 'Contact [email protected] if you have questions.', errors))
2236 return results
2237
2238
Daniel Cheng4dcdb6b2017-04-13 08:30:172239def _ExtractAddRulesFromParsedDeps(parsed_deps):
2240 """Extract the rules that add dependencies from a parsed DEPS file.
2241
2242 Args:
2243 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2244 add_rules = set()
2245 add_rules.update([
2246 rule[1:] for rule in parsed_deps.get('include_rules', [])
2247 if rule.startswith('+') or rule.startswith('!')
2248 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502249 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172250 {}).iteritems():
2251 add_rules.update([
2252 rule[1:] for rule in rules
2253 if rule.startswith('+') or rule.startswith('!')
2254 ])
2255 return add_rules
2256
2257
2258def _ParseDeps(contents):
2259 """Simple helper for parsing DEPS files."""
2260 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172261 class _VarImpl:
2262
2263 def __init__(self, local_scope):
2264 self._local_scope = local_scope
2265
2266 def Lookup(self, var_name):
2267 """Implements the Var syntax."""
2268 try:
2269 return self._local_scope['vars'][var_name]
2270 except KeyError:
2271 raise Exception('Var is not defined: %s' % var_name)
2272
2273 local_scope = {}
2274 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172275 'Var': _VarImpl(local_scope).Lookup,
2276 }
2277 exec contents in global_scope, local_scope
2278 return local_scope
2279
2280
2281def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082282 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412283 a set of DEPS entries that we should look up.
2284
2285 For a directory (rather than a specific filename) we fake a path to
2286 a specific filename by adding /DEPS. This is chosen as a file that
2287 will seldom or never be subject to per-file include_rules.
2288 """
[email protected]2b438d62013-11-14 17:54:142289 # We ignore deps entries on auto-generated directories.
2290 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082291
Daniel Cheng4dcdb6b2017-04-13 08:30:172292 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2293 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2294
2295 added_deps = new_deps.difference(old_deps)
2296
[email protected]2b438d62013-11-14 17:54:142297 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172298 for added_dep in added_deps:
2299 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2300 continue
2301 # Assume that a rule that ends in .h is a rule for a specific file.
2302 if added_dep.endswith('.h'):
2303 results.add(added_dep)
2304 else:
2305 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082306 return results
2307
2308
[email protected]e871964c2013-05-13 14:14:552309def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2310 """When a dependency prefixed with + is added to a DEPS file, we
2311 want to make sure that the change is reviewed by an OWNER of the
2312 target file or directory, to avoid layering violations from being
2313 introduced. This check verifies that this happens.
2314 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172315 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242316
2317 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492318 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242319 for f in input_api.AffectedFiles(include_deletes=False,
2320 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552321 filename = input_api.os_path.basename(f.LocalPath())
2322 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172323 virtual_depended_on_files.update(_CalculateAddedDeps(
2324 input_api.os_path,
2325 '\n'.join(f.OldContents()),
2326 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552327
[email protected]e871964c2013-05-13 14:14:552328 if not virtual_depended_on_files:
2329 return []
2330
2331 if input_api.is_committing:
2332 if input_api.tbr:
2333 return [output_api.PresubmitNotifyResult(
2334 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272335 if input_api.dry_run:
2336 return [output_api.PresubmitNotifyResult(
2337 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552338 if not input_api.change.issue:
2339 return [output_api.PresubmitError(
2340 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402341 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552342 output = output_api.PresubmitError
2343 else:
2344 output = output_api.PresubmitNotifyResult
2345
2346 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502347 owner_email, reviewers = (
2348 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2349 input_api,
2350 owners_db.email_regexp,
2351 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552352
2353 owner_email = owner_email or input_api.change.author_email
2354
[email protected]de4f7d22013-05-23 14:27:462355 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512356 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462357 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552358 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2359 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412360
2361 # We strip the /DEPS part that was added by
2362 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2363 # directory.
2364 def StripDeps(path):
2365 start_deps = path.rfind('/DEPS')
2366 if start_deps != -1:
2367 return path[:start_deps]
2368 else:
2369 return path
2370 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552371 for path in missing_files]
2372
2373 if unapproved_dependencies:
2374 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152375 output('You need LGTM from owners of depends-on paths in DEPS that were '
2376 'modified in this CL:\n %s' %
2377 '\n '.join(sorted(unapproved_dependencies)))]
2378 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2379 output_list.append(output(
2380 'Suggested missing target path OWNERS:\n %s' %
2381 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552382 return output_list
2383
2384 return []
2385
2386
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492387# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402388def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492389 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402390 black_list = (_EXCLUDED_PATHS +
2391 _TEST_CODE_EXCLUDED_PATHS +
2392 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042393 (r"^base[\\/]logging\.h$",
2394 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222395 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042396 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2397 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2398 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122399 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182400 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152401 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032402 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152403 r"^chrome[\\/]chrome_cleaner[\\/].*",
2404 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2405 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042406 r"^chromecast[\\/]",
2407 r"^cloud_print[\\/]",
2408 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482409 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:042410 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:312411 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042412 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462413 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042414 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462415 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042416 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252417 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042418 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2419 r"^courgette[\\/]courgette_tool\.cc$",
2420 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272421 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332422 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042423 r"^ipc[\\/]ipc_logging\.cc$",
2424 r"^native_client_sdk[\\/]",
2425 r"^remoting[\\/]base[\\/]logging\.h$",
2426 r"^remoting[\\/]host[\\/].*",
2427 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332428 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
2429 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042430 r"^tools[\\/]",
2431 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2432 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332433 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402434 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492435 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402436
thomasanderson625d3932017-03-29 07:16:582437 log_info = set([])
2438 printf = set([])
[email protected]85218562013-11-22 07:41:402439
2440 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582441 for _, line in f.ChangedContents():
2442 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2443 log_info.add(f.LocalPath())
2444 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2445 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372446
thomasanderson625d3932017-03-29 07:16:582447 if input_api.re.search(r"\bprintf\(", line):
2448 printf.add(f.LocalPath())
2449 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2450 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402451
2452 if log_info:
2453 return [output_api.PresubmitError(
2454 'These files spam the console log with LOG(INFO):',
2455 items=log_info)]
2456 if printf:
2457 return [output_api.PresubmitError(
2458 'These files spam the console log with printf/fprintf:',
2459 items=printf)]
2460 return []
2461
2462
[email protected]49aa76a2013-12-04 06:59:162463def _CheckForAnonymousVariables(input_api, output_api):
2464 """These types are all expected to hold locks while in scope and
2465 so should never be anonymous (which causes them to be immediately
2466 destroyed)."""
2467 they_who_must_be_named = [
2468 'base::AutoLock',
2469 'base::AutoReset',
2470 'base::AutoUnlock',
2471 'SkAutoAlphaRestore',
2472 'SkAutoBitmapShaderInstall',
2473 'SkAutoBlitterChoose',
2474 'SkAutoBounderCommit',
2475 'SkAutoCallProc',
2476 'SkAutoCanvasRestore',
2477 'SkAutoCommentBlock',
2478 'SkAutoDescriptor',
2479 'SkAutoDisableDirectionCheck',
2480 'SkAutoDisableOvalCheck',
2481 'SkAutoFree',
2482 'SkAutoGlyphCache',
2483 'SkAutoHDC',
2484 'SkAutoLockColors',
2485 'SkAutoLockPixels',
2486 'SkAutoMalloc',
2487 'SkAutoMaskFreeImage',
2488 'SkAutoMutexAcquire',
2489 'SkAutoPathBoundsUpdate',
2490 'SkAutoPDFRelease',
2491 'SkAutoRasterClipValidate',
2492 'SkAutoRef',
2493 'SkAutoTime',
2494 'SkAutoTrace',
2495 'SkAutoUnref',
2496 ]
2497 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2498 # bad: base::AutoLock(lock.get());
2499 # not bad: base::AutoLock lock(lock.get());
2500 bad_pattern = input_api.re.compile(anonymous)
2501 # good: new base::AutoLock(lock.get())
2502 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2503 errors = []
2504
2505 for f in input_api.AffectedFiles():
2506 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2507 continue
2508 for linenum, line in f.ChangedContents():
2509 if bad_pattern.search(line) and not good_pattern.search(line):
2510 errors.append('%s:%d' % (f.LocalPath(), linenum))
2511
2512 if errors:
2513 return [output_api.PresubmitError(
2514 'These lines create anonymous variables that need to be named:',
2515 items=errors)]
2516 return []
2517
2518
Peter Kasting4844e46e2018-02-23 07:27:102519def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532520 # Returns whether |template_str| is of the form <T, U...> for some types T
2521 # and U. Assumes that |template_str| is already in the form <...>.
2522 def HasMoreThanOneArg(template_str):
2523 # Level of <...> nesting.
2524 nesting = 0
2525 for c in template_str:
2526 if c == '<':
2527 nesting += 1
2528 elif c == '>':
2529 nesting -= 1
2530 elif c == ',' and nesting == 1:
2531 return True
2532 return False
2533
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492534 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102535 sources = lambda affected_file: input_api.FilterSourceFile(
2536 affected_file,
2537 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2538 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492539 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552540
2541 # Pattern to capture a single "<...>" block of template arguments. It can
2542 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2543 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2544 # latter would likely require counting that < and > match, which is not
2545 # expressible in regular languages. Should the need arise, one can introduce
2546 # limited counting (matching up to a total number of nesting depth), which
2547 # should cover all practical cases for already a low nesting limit.
2548 template_arg_pattern = (
2549 r'<[^>]*' # Opening block of <.
2550 r'>([^<]*>)?') # Closing block of >.
2551 # Prefix expressing that whatever follows is not already inside a <...>
2552 # block.
2553 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102554 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552555 not_inside_template_arg_pattern
2556 + r'\bstd::unique_ptr'
2557 + template_arg_pattern
2558 + r'\(\)')
2559
2560 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2561 template_arg_no_array_pattern = (
2562 r'<[^>]*[^]]' # Opening block of <.
2563 r'>([^(<]*[^]]>)?') # Closing block of >.
2564 # Prefix saying that what follows is the start of an expression.
2565 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2566 # Suffix saying that what follows are call parentheses with a non-empty list
2567 # of arguments.
2568 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532569 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552570 return_construct_pattern = input_api.re.compile(
2571 start_of_expr_pattern
2572 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532573 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552574 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532575 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552576 + nonempty_arg_list_pattern)
2577
Vaclav Brozek851d9602018-04-04 16:13:052578 problems_constructor = []
2579 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102580 for f in input_api.AffectedSourceFiles(sources):
2581 for line_number, line in f.ChangedContents():
2582 # Disallow:
2583 # return std::unique_ptr<T>(foo);
2584 # bar = std::unique_ptr<T>(foo);
2585 # But allow:
2586 # return std::unique_ptr<T[]>(foo);
2587 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532588 # And also allow cases when the second template argument is present. Those
2589 # cases cannot be handled by std::make_unique:
2590 # return std::unique_ptr<T, U>(foo);
2591 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052592 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532593 return_construct_result = return_construct_pattern.search(line)
2594 if return_construct_result and not HasMoreThanOneArg(
2595 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052596 problems_constructor.append(
2597 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102598 # Disallow:
2599 # std::unique_ptr<T>()
2600 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052601 problems_nullptr.append(
2602 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2603
2604 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162605 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052606 errors.append(output_api.PresubmitError(
2607 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162608 problems_nullptr))
2609 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052610 errors.append(output_api.PresubmitError(
2611 'The following files use explicit std::unique_ptr constructor.'
2612 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162613 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102614 return errors
2615
2616
[email protected]999261d2014-03-03 20:08:082617def _CheckUserActionUpdate(input_api, output_api):
2618 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522619 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082620 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522621 # If actions.xml is already included in the changelist, the PRESUBMIT
2622 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082623 return []
2624
[email protected]999261d2014-03-03 20:08:082625 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2626 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522627 current_actions = None
[email protected]999261d2014-03-03 20:08:082628 for f in input_api.AffectedFiles(file_filter=file_filter):
2629 for line_num, line in f.ChangedContents():
2630 match = input_api.re.search(action_re, line)
2631 if match:
[email protected]2f92dec2014-03-07 19:21:522632 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2633 # loaded only once.
2634 if not current_actions:
2635 with open('tools/metrics/actions/actions.xml') as actions_f:
2636 current_actions = actions_f.read()
2637 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082638 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522639 action = 'name="{0}"'.format(action_name)
2640 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082641 return [output_api.PresubmitPromptWarning(
2642 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522643 'tools/metrics/actions/actions.xml. Please run '
2644 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082645 % (f.LocalPath(), line_num, action_name))]
2646 return []
2647
2648
Daniel Cheng13ca61a882017-08-25 15:11:252649def _ImportJSONCommentEater(input_api):
2650 import sys
2651 sys.path = sys.path + [input_api.os_path.join(
2652 input_api.PresubmitLocalPath(),
2653 'tools', 'json_comment_eater')]
2654 import json_comment_eater
2655 return json_comment_eater
2656
2657
[email protected]99171a92014-06-03 08:44:472658def _GetJSONParseError(input_api, filename, eat_comments=True):
2659 try:
2660 contents = input_api.ReadFile(filename)
2661 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252662 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132663 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472664
2665 input_api.json.loads(contents)
2666 except ValueError as e:
2667 return e
2668 return None
2669
2670
2671def _GetIDLParseError(input_api, filename):
2672 try:
2673 contents = input_api.ReadFile(filename)
2674 idl_schema = input_api.os_path.join(
2675 input_api.PresubmitLocalPath(),
2676 'tools', 'json_schema_compiler', 'idl_schema.py')
2677 process = input_api.subprocess.Popen(
2678 [input_api.python_executable, idl_schema],
2679 stdin=input_api.subprocess.PIPE,
2680 stdout=input_api.subprocess.PIPE,
2681 stderr=input_api.subprocess.PIPE,
2682 universal_newlines=True)
2683 (_, error) = process.communicate(input=contents)
2684 return error or None
2685 except ValueError as e:
2686 return e
2687
2688
2689def _CheckParseErrors(input_api, output_api):
2690 """Check that IDL and JSON files do not contain syntax errors."""
2691 actions = {
2692 '.idl': _GetIDLParseError,
2693 '.json': _GetJSONParseError,
2694 }
[email protected]99171a92014-06-03 08:44:472695 # Most JSON files are preprocessed and support comments, but these do not.
2696 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042697 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472698 ]
2699 # Only run IDL checker on files in these directories.
2700 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042701 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2702 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472703 ]
2704
2705 def get_action(affected_file):
2706 filename = affected_file.LocalPath()
2707 return actions.get(input_api.os_path.splitext(filename)[1])
2708
[email protected]99171a92014-06-03 08:44:472709 def FilterFile(affected_file):
2710 action = get_action(affected_file)
2711 if not action:
2712 return False
2713 path = affected_file.LocalPath()
2714
Sean Kau46e29bc2017-08-28 16:31:162715 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472716 return False
2717
2718 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162719 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472720 return False
2721 return True
2722
2723 results = []
2724 for affected_file in input_api.AffectedFiles(
2725 file_filter=FilterFile, include_deletes=False):
2726 action = get_action(affected_file)
2727 kwargs = {}
2728 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162729 _MatchesFile(input_api, json_no_comments_patterns,
2730 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472731 kwargs['eat_comments'] = False
2732 parse_error = action(input_api,
2733 affected_file.AbsoluteLocalPath(),
2734 **kwargs)
2735 if parse_error:
2736 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2737 (affected_file.LocalPath(), parse_error)))
2738 return results
2739
2740
[email protected]760deea2013-12-10 19:33:492741def _CheckJavaStyle(input_api, output_api):
2742 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472743 import sys
[email protected]760deea2013-12-10 19:33:492744 original_sys_path = sys.path
2745 try:
2746 sys.path = sys.path + [input_api.os_path.join(
2747 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2748 import checkstyle
2749 finally:
2750 # Restore sys.path to what it was before.
2751 sys.path = original_sys_path
2752
2753 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092754 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512755 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492756
2757
Nate Fischerdfd9812e2019-07-18 22:03:002758def _CheckPythonDevilInit(input_api, output_api):
2759 """Checks to make sure devil is initialized correctly in python scripts."""
2760 script_common_initialize_pattern = input_api.re.compile(
2761 r'script_common\.InitializeEnvironment\(')
2762 devil_env_config_initialize = input_api.re.compile(
2763 r'devil_env\.config\.Initialize\(')
2764
2765 errors = []
2766
2767 sources = lambda affected_file: input_api.FilterSourceFile(
2768 affected_file,
2769 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2770 (r'^build[\\/]android[\\/]devil_chromium\.py',
2771 r'^third_party[\\/].*',)),
2772 white_list=[r'.*\.py$'])
2773
2774 for f in input_api.AffectedSourceFiles(sources):
2775 for line_num, line in f.ChangedContents():
2776 if (script_common_initialize_pattern.search(line) or
2777 devil_env_config_initialize.search(line)):
2778 errors.append("%s:%d" % (f.LocalPath(), line_num))
2779
2780 results = []
2781
2782 if errors:
2783 results.append(output_api.PresubmitError(
2784 'Devil initialization should always be done using '
2785 'devil_chromium.Initialize() in the chromium project, to use better '
2786 'defaults for dependencies (ex. up-to-date version of adb).',
2787 errors))
2788
2789 return results
2790
2791
Sean Kau46e29bc2017-08-28 16:31:162792def _MatchesFile(input_api, patterns, path):
2793 for pattern in patterns:
2794 if input_api.re.search(pattern, path):
2795 return True
2796 return False
2797
2798
Daniel Cheng7052cdf2017-11-21 19:23:292799def _GetOwnersFilesToCheckForIpcOwners(input_api):
2800 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172801
Daniel Cheng7052cdf2017-11-21 19:23:292802 Returns:
2803 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2804 contain to cover IPC-related files with noparent reviewer rules.
2805 """
2806 # Whether or not a file affects IPC is (mostly) determined by a simple list
2807 # of filename patterns.
dchenge07de812016-06-20 19:27:172808 file_patterns = [
palmerb19a0932017-01-24 04:00:312809 # Legacy IPC:
dchenge07de812016-06-20 19:27:172810 '*_messages.cc',
2811 '*_messages*.h',
2812 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312813 # Mojo IPC:
dchenge07de812016-06-20 19:27:172814 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472815 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172816 '*_struct_traits*.*',
2817 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312818 '*.typemap',
2819 # Android native IPC:
2820 '*.aidl',
2821 # Blink uses a different file naming convention:
2822 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472823 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172824 '*StructTraits*.*',
2825 '*TypeConverter*.*',
2826 ]
2827
scottmg7a6ed5ba2016-11-04 18:22:042828 # These third_party directories do not contain IPCs, but contain files
2829 # matching the above patterns, which trigger false positives.
2830 exclude_paths = [
2831 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232832 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062833 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292834 'third_party/win_build_output/*',
Clark DuVallfb37334c2019-09-03 18:32:172835 # These aidl files are just used to communicate between class loaders
2836 # running in the same process.
2837 'weblayer/browser/java/org/chromium/weblayer_private/aidl/*',
scottmg7a6ed5ba2016-11-04 18:22:042838 ]
2839
dchenge07de812016-06-20 19:27:172840 # Dictionary mapping an OWNERS file path to Patterns.
2841 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2842 # rules ) to a PatternEntry.
2843 # PatternEntry is a dictionary with two keys:
2844 # - 'files': the files that are matched by this pattern
2845 # - 'rules': the per-file rules needed for this pattern
2846 # For example, if we expect OWNERS file to contain rules for *.mojom and
2847 # *_struct_traits*.*, Patterns might look like this:
2848 # {
2849 # '*.mojom': {
2850 # 'files': ...,
2851 # 'rules': [
2852 # 'per-file *.mojom=set noparent',
2853 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2854 # ],
2855 # },
2856 # '*_struct_traits*.*': {
2857 # 'files': ...,
2858 # 'rules': [
2859 # 'per-file *_struct_traits*.*=set noparent',
2860 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2861 # ],
2862 # },
2863 # }
2864 to_check = {}
2865
Daniel Cheng13ca61a882017-08-25 15:11:252866 def AddPatternToCheck(input_file, pattern):
2867 owners_file = input_api.os_path.join(
2868 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2869 if owners_file not in to_check:
2870 to_check[owners_file] = {}
2871 if pattern not in to_check[owners_file]:
2872 to_check[owners_file][pattern] = {
2873 'files': [],
2874 'rules': [
2875 'per-file %s=set noparent' % pattern,
2876 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2877 ]
2878 }
Vaclav Brozekd5de76a2018-03-17 07:57:502879 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252880
dchenge07de812016-06-20 19:27:172881 # Iterate through the affected files to see what we actually need to check
2882 # for. We should only nag patch authors about per-file rules if a file in that
2883 # directory would match that pattern. If a directory only contains *.mojom
2884 # files and no *_messages*.h files, we should only nag about rules for
2885 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252886 for f in input_api.AffectedFiles(include_deletes=False):
2887 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362888 # affected files for .json, .cc, and .h files which look like they contain
2889 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162890 if (f.LocalPath().endswith('.json') and
2891 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2892 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252893 json_comment_eater = _ImportJSONCommentEater(input_api)
2894 mostly_json_lines = '\n'.join(f.NewContents())
2895 # Comments aren't allowed in strict JSON, so filter them out.
2896 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432897 try:
2898 json_content = input_api.json.loads(json_lines)
2899 except:
2900 # There's another PRESUBMIT check that already verifies that JSON files
2901 # are not invalid, so no need to emit another warning here.
2902 continue
Daniel Cheng13ca61a882017-08-25 15:11:252903 if 'interface_provider_specs' in json_content:
2904 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362905 else:
2906 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2907 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2908 if (manifest_pattern.search(f.LocalPath()) and not
2909 test_manifest_pattern.search(f.LocalPath())):
2910 # We expect all actual service manifest files to contain at least one
2911 # qualified reference to service_manager::Manifest.
2912 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2913 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172914 for pattern in file_patterns:
2915 if input_api.fnmatch.fnmatch(
2916 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042917 skip = False
2918 for exclude in exclude_paths:
2919 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2920 skip = True
2921 break
2922 if skip:
2923 continue
Daniel Cheng13ca61a882017-08-25 15:11:252924 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172925 break
2926
Daniel Cheng7052cdf2017-11-21 19:23:292927 return to_check
2928
2929
2930def _CheckIpcOwners(input_api, output_api):
2931 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2932 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2933
2934 if to_check:
2935 # If there are any OWNERS files to check, there are IPC-related changes in
2936 # this CL. Auto-CC the review list.
2937 output_api.AppendCC('[email protected]')
2938
2939 # Go through the OWNERS files to check, filtering out rules that are already
2940 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172941 for owners_file, patterns in to_check.iteritems():
2942 try:
2943 with file(owners_file) as f:
2944 lines = set(f.read().splitlines())
2945 for entry in patterns.itervalues():
2946 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2947 ]
2948 except IOError:
2949 # No OWNERS file, so all the rules are definitely missing.
2950 continue
2951
2952 # All the remaining lines weren't found in OWNERS files, so emit an error.
2953 errors = []
2954 for owners_file, patterns in to_check.iteritems():
2955 missing_lines = []
2956 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502957 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172958 missing_lines.extend(entry['rules'])
2959 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2960 if missing_lines:
2961 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052962 'Because of the presence of files:\n%s\n\n'
2963 '%s needs the following %d lines added:\n\n%s' %
2964 ('\n'.join(files), owners_file, len(missing_lines),
2965 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172966
2967 results = []
2968 if errors:
vabrf5ce3bf92016-07-11 14:52:412969 if input_api.is_committing:
2970 output = output_api.PresubmitError
2971 else:
2972 output = output_api.PresubmitPromptWarning
2973 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592974 'Found OWNERS files that need to be updated for IPC security ' +
2975 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172976 long_text='\n\n'.join(errors)))
2977
2978 return results
2979
2980
jbriance9e12f162016-11-25 07:57:502981def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312982 """Checks that added or removed lines in non third party affected
2983 header files do not lead to new useless class or struct forward
2984 declaration.
jbriance9e12f162016-11-25 07:57:502985 """
2986 results = []
2987 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2988 input_api.re.MULTILINE)
2989 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2990 input_api.re.MULTILINE)
2991 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312992 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192993 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492994 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312995 continue
2996
jbriance9e12f162016-11-25 07:57:502997 if not f.LocalPath().endswith('.h'):
2998 continue
2999
3000 contents = input_api.ReadFile(f)
3001 fwd_decls = input_api.re.findall(class_pattern, contents)
3002 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3003
3004 useless_fwd_decls = []
3005 for decl in fwd_decls:
3006 count = sum(1 for _ in input_api.re.finditer(
3007 r'\b%s\b' % input_api.re.escape(decl), contents))
3008 if count == 1:
3009 useless_fwd_decls.append(decl)
3010
3011 if not useless_fwd_decls:
3012 continue
3013
3014 for line in f.GenerateScmDiff().splitlines():
3015 if (line.startswith('-') and not line.startswith('--') or
3016 line.startswith('+') and not line.startswith('++')):
3017 for decl in useless_fwd_decls:
3018 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3019 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243020 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503021 (f.LocalPath(), decl)))
3022 useless_fwd_decls.remove(decl)
3023
3024 return results
3025
Jinsong Fan91ebbbd2019-04-16 14:57:173026def _CheckAndroidDebuggableBuild(input_api, output_api):
3027 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3028 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3029 this is a debuggable build of Android.
3030 """
3031 build_type_check_pattern = input_api.re.compile(
3032 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3033
3034 errors = []
3035
3036 sources = lambda affected_file: input_api.FilterSourceFile(
3037 affected_file,
3038 black_list=(_EXCLUDED_PATHS +
3039 _TEST_CODE_EXCLUDED_PATHS +
3040 input_api.DEFAULT_BLACK_LIST +
3041 (r"^android_webview[\\/]support_library[\\/]"
3042 "boundary_interfaces[\\/]",
3043 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3044 r'^third_party[\\/].*',
3045 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3046 r"webview[\\/]chromium[\\/]License.*",)),
3047 white_list=[r'.*\.java$'])
3048
3049 for f in input_api.AffectedSourceFiles(sources):
3050 for line_num, line in f.ChangedContents():
3051 if build_type_check_pattern.search(line):
3052 errors.append("%s:%d" % (f.LocalPath(), line_num))
3053
3054 results = []
3055
3056 if errors:
3057 results.append(output_api.PresubmitPromptWarning(
3058 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3059 ' Please use BuildInfo.isDebugAndroid() instead.',
3060 errors))
3061
3062 return results
jbriance9e12f162016-11-25 07:57:503063
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493064# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293065def _CheckAndroidToastUsage(input_api, output_api):
3066 """Checks that code uses org.chromium.ui.widget.Toast instead of
3067 android.widget.Toast (Chromium Toast doesn't force hardware
3068 acceleration on low-end devices, saving memory).
3069 """
3070 toast_import_pattern = input_api.re.compile(
3071 r'^import android\.widget\.Toast;$')
3072
3073 errors = []
3074
3075 sources = lambda affected_file: input_api.FilterSourceFile(
3076 affected_file,
3077 black_list=(_EXCLUDED_PATHS +
3078 _TEST_CODE_EXCLUDED_PATHS +
3079 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043080 (r'^chromecast[\\/].*',
3081 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493082 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293083
3084 for f in input_api.AffectedSourceFiles(sources):
3085 for line_num, line in f.ChangedContents():
3086 if toast_import_pattern.search(line):
3087 errors.append("%s:%d" % (f.LocalPath(), line_num))
3088
3089 results = []
3090
3091 if errors:
3092 results.append(output_api.PresubmitError(
3093 'android.widget.Toast usage is detected. Android toasts use hardware'
3094 ' acceleration, and can be\ncostly on low-end devices. Please use'
3095 ' org.chromium.ui.widget.Toast instead.\n'
3096 'Contact [email protected] if you have any questions.',
3097 errors))
3098
3099 return results
3100
3101
dgnaa68d5e2015-06-10 10:08:223102def _CheckAndroidCrLogUsage(input_api, output_api):
3103 """Checks that new logs using org.chromium.base.Log:
3104 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513105 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223106 """
pkotwicza1dd0b002016-05-16 14:41:043107
torne89540622017-03-24 19:41:303108 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043109 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303110 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043111 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303112 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043113 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3114 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093115 # The customtabs_benchmark is a small app that does not depend on Chromium
3116 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043117 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043118 ]
3119
dgnaa68d5e2015-06-10 10:08:223120 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123121 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3122 class_in_base_pattern = input_api.re.compile(
3123 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3124 has_some_log_import_pattern = input_api.re.compile(
3125 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223126 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:123127 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:223128 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:513129 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:223130 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223131
Vincent Scheib16d7b272015-09-15 18:09:073132 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:223133 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493134 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043135 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123136
dgnaa68d5e2015-06-10 10:08:223137 tag_decl_errors = []
3138 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123139 tag_errors = []
dgn38736db2015-09-18 19:20:513140 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123141 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223142
3143 for f in input_api.AffectedSourceFiles(sources):
3144 file_content = input_api.ReadFile(f)
3145 has_modified_logs = False
3146
3147 # Per line checks
dgn87d9fb62015-06-12 09:15:123148 if (cr_log_import_pattern.search(file_content) or
3149 (class_in_base_pattern.search(file_content) and
3150 not has_some_log_import_pattern.search(file_content))):
3151 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223152 for line_num, line in f.ChangedContents():
3153
3154 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123155 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223156 if match:
3157 has_modified_logs = True
3158
3159 # Make sure it uses "TAG"
3160 if not match.group('tag') == 'TAG':
3161 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123162 else:
3163 # Report non cr Log function calls in changed lines
3164 for line_num, line in f.ChangedContents():
3165 if log_call_pattern.search(line):
3166 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223167
3168 # Per file checks
3169 if has_modified_logs:
3170 # Make sure the tag is using the "cr" prefix and is not too long
3171 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513172 tag_name = match.group('name') if match else None
3173 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223174 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513175 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223176 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513177 elif '.' in tag_name:
3178 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223179
3180 results = []
3181 if tag_decl_errors:
3182 results.append(output_api.PresubmitPromptWarning(
3183 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513184 '"private static final String TAG = "<package tag>".\n'
3185 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223186 tag_decl_errors))
3187
3188 if tag_length_errors:
3189 results.append(output_api.PresubmitError(
3190 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513191 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223192 tag_length_errors))
3193
3194 if tag_errors:
3195 results.append(output_api.PresubmitPromptWarning(
3196 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3197 tag_errors))
3198
dgn87d9fb62015-06-12 09:15:123199 if util_log_errors:
dgn4401aa52015-04-29 16:26:173200 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123201 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3202 util_log_errors))
3203
dgn38736db2015-09-18 19:20:513204 if tag_with_dot_errors:
3205 results.append(output_api.PresubmitPromptWarning(
3206 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3207 tag_with_dot_errors))
3208
dgn4401aa52015-04-29 16:26:173209 return results
3210
3211
Yoland Yanb92fa522017-08-28 17:37:063212def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3213 """Checks that junit.framework.* is no longer used."""
3214 deprecated_junit_framework_pattern = input_api.re.compile(
3215 r'^import junit\.framework\..*;',
3216 input_api.re.MULTILINE)
3217 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493218 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063219 errors = []
3220 for f in input_api.AffectedFiles(sources):
3221 for line_num, line in f.ChangedContents():
3222 if deprecated_junit_framework_pattern.search(line):
3223 errors.append("%s:%d" % (f.LocalPath(), line_num))
3224
3225 results = []
3226 if errors:
3227 results.append(output_api.PresubmitError(
3228 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3229 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3230 ' if you have any question.', errors))
3231 return results
3232
3233
3234def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3235 """Checks that if new Java test classes have inheritance.
3236 Either the new test class is JUnit3 test or it is a JUnit4 test class
3237 with a base class, either case is undesirable.
3238 """
3239 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3240
3241 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493242 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063243 errors = []
3244 for f in input_api.AffectedFiles(sources):
3245 if not f.OldContents():
3246 class_declaration_start_flag = False
3247 for line_num, line in f.ChangedContents():
3248 if class_declaration_pattern.search(line):
3249 class_declaration_start_flag = True
3250 if class_declaration_start_flag and ' extends ' in line:
3251 errors.append('%s:%d' % (f.LocalPath(), line_num))
3252 if '{' in line:
3253 class_declaration_start_flag = False
3254
3255 results = []
3256 if errors:
3257 results.append(output_api.PresubmitPromptWarning(
3258 'The newly created files include Test classes that inherits from base'
3259 ' class. Please do not use inheritance in JUnit4 tests or add new'
3260 ' JUnit3 tests. Contact [email protected] if you have any'
3261 ' questions.', errors))
3262 return results
3263
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203264
yolandyan45001472016-12-21 21:12:423265def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3266 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3267 deprecated_annotation_import_pattern = input_api.re.compile(
3268 r'^import android\.test\.suitebuilder\.annotation\..*;',
3269 input_api.re.MULTILINE)
3270 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493271 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423272 errors = []
3273 for f in input_api.AffectedFiles(sources):
3274 for line_num, line in f.ChangedContents():
3275 if deprecated_annotation_import_pattern.search(line):
3276 errors.append("%s:%d" % (f.LocalPath(), line_num))
3277
3278 results = []
3279 if errors:
3280 results.append(output_api.PresubmitError(
3281 'Annotations in android.test.suitebuilder.annotation have been'
3282 ' deprecated since API level 24. Please use android.support.test.filters'
3283 ' from //third_party/android_support_test_runner:runner_java instead.'
3284 ' Contact [email protected] if you have any questions.', errors))
3285 return results
3286
3287
agrieve7b6479d82015-10-07 14:24:223288def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3289 """Checks if MDPI assets are placed in a correct directory."""
3290 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3291 ('/res/drawable/' in f.LocalPath() or
3292 '/res/drawable-ldrtl/' in f.LocalPath()))
3293 errors = []
3294 for f in input_api.AffectedFiles(include_deletes=False,
3295 file_filter=file_filter):
3296 errors.append(' %s' % f.LocalPath())
3297
3298 results = []
3299 if errors:
3300 results.append(output_api.PresubmitError(
3301 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3302 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3303 '/res/drawable-ldrtl/.\n'
3304 'Contact [email protected] if you have questions.', errors))
3305 return results
3306
3307
Nate Fischer535972b2017-09-16 01:06:183308def _CheckAndroidWebkitImports(input_api, output_api):
3309 """Checks that code uses org.chromium.base.Callback instead of
3310 android.widget.ValueCallback except in the WebView glue layer.
3311 """
3312 valuecallback_import_pattern = input_api.re.compile(
3313 r'^import android\.webkit\.ValueCallback;$')
3314
3315 errors = []
3316
3317 sources = lambda affected_file: input_api.FilterSourceFile(
3318 affected_file,
3319 black_list=(_EXCLUDED_PATHS +
3320 _TEST_CODE_EXCLUDED_PATHS +
3321 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043322 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493323 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183324
3325 for f in input_api.AffectedSourceFiles(sources):
3326 for line_num, line in f.ChangedContents():
3327 if valuecallback_import_pattern.search(line):
3328 errors.append("%s:%d" % (f.LocalPath(), line_num))
3329
3330 results = []
3331
3332 if errors:
3333 results.append(output_api.PresubmitError(
3334 'android.webkit.ValueCallback usage is detected outside of the glue'
3335 ' layer. To stay compatible with the support library, android.webkit.*'
3336 ' classes should only be used inside the glue layer and'
3337 ' org.chromium.base.Callback should be used instead.',
3338 errors))
3339
3340 return results
3341
3342
Becky Zhou7c69b50992018-12-10 19:37:573343def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3344 """Checks Android XML styles """
3345 import sys
3346 original_sys_path = sys.path
3347 try:
3348 sys.path = sys.path + [input_api.os_path.join(
3349 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3350 import checkxmlstyle
3351 finally:
3352 # Restore sys.path to what it was before.
3353 sys.path = original_sys_path
3354
3355 if is_check_on_upload:
3356 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3357 else:
3358 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3359
3360
agrievef32bcc72016-04-04 14:57:403361class PydepsChecker(object):
3362 def __init__(self, input_api, pydeps_files):
3363 self._file_cache = {}
3364 self._input_api = input_api
3365 self._pydeps_files = pydeps_files
3366
3367 def _LoadFile(self, path):
3368 """Returns the list of paths within a .pydeps file relative to //."""
3369 if path not in self._file_cache:
3370 with open(path) as f:
3371 self._file_cache[path] = f.read()
3372 return self._file_cache[path]
3373
3374 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3375 """Returns an interable of paths within the .pydep, relativized to //."""
3376 os_path = self._input_api.os_path
3377 pydeps_dir = os_path.dirname(pydeps_path)
3378 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3379 if not l.startswith('*'))
3380 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3381
3382 def _CreateFilesToPydepsMap(self):
3383 """Returns a map of local_path -> list_of_pydeps."""
3384 ret = {}
3385 for pydep_local_path in self._pydeps_files:
3386 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3387 ret.setdefault(path, []).append(pydep_local_path)
3388 return ret
3389
3390 def ComputeAffectedPydeps(self):
3391 """Returns an iterable of .pydeps files that might need regenerating."""
3392 affected_pydeps = set()
3393 file_to_pydeps_map = None
3394 for f in self._input_api.AffectedFiles(include_deletes=True):
3395 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463396 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3397 # subrepositories. We can't figure out which files change, so re-check
3398 # all files.
3399 # Changes to print_python_deps.py affect all .pydeps.
3400 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403401 return self._pydeps_files
3402 elif local_path.endswith('.pydeps'):
3403 if local_path in self._pydeps_files:
3404 affected_pydeps.add(local_path)
3405 elif local_path.endswith('.py'):
3406 if file_to_pydeps_map is None:
3407 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3408 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3409 return affected_pydeps
3410
3411 def DetermineIfStale(self, pydeps_path):
3412 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413413 import difflib
John Budorick47ca3fe2018-02-10 00:53:103414 import os
3415
agrievef32bcc72016-04-04 14:57:403416 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3417 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103418 env = dict(os.environ)
3419 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403420 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103421 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413422 old_contents = old_pydeps_data[2:]
3423 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403424 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413425 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403426
3427
Tibor Goldschwendt360793f72019-06-25 18:23:493428def _ParseGclientArgs():
3429 args = {}
3430 with open('build/config/gclient_args.gni', 'r') as f:
3431 for line in f:
3432 line = line.strip()
3433 if not line or line.startswith('#'):
3434 continue
3435 attribute, value = line.split('=')
3436 args[attribute.strip()] = value.strip()
3437 return args
3438
3439
agrievef32bcc72016-04-04 14:57:403440def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3441 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403442 # This check is for Python dependency lists (.pydeps files), and involves
3443 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3444 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283445 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003446 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493447 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403448 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3449 results = []
3450 # First, check for new / deleted .pydeps.
3451 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033452 # Check whether we are running the presubmit check for a file in src.
3453 # f.LocalPath is relative to repo (src, or internal repo).
3454 # os_path.exists is relative to src repo.
3455 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3456 # to src and we can conclude that the pydeps is in src.
3457 if input_api.os_path.exists(f.LocalPath()):
3458 if f.LocalPath().endswith('.pydeps'):
3459 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3460 results.append(output_api.PresubmitError(
3461 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3462 'remove %s' % f.LocalPath()))
3463 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3464 results.append(output_api.PresubmitError(
3465 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3466 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403467
3468 if results:
3469 return results
3470
3471 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3472
3473 for pydep_path in checker.ComputeAffectedPydeps():
3474 try:
phajdan.jr0d9878552016-11-04 10:49:413475 result = checker.DetermineIfStale(pydep_path)
3476 if result:
3477 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403478 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413479 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3480 'To regenerate, run:\n\n %s' %
3481 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403482 except input_api.subprocess.CalledProcessError as error:
3483 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3484 long_text=error.output)]
3485
3486 return results
3487
3488
glidere61efad2015-02-18 17:39:433489def _CheckSingletonInHeaders(input_api, output_api):
3490 """Checks to make sure no header files have |Singleton<|."""
3491 def FileFilter(affected_file):
3492 # It's ok for base/memory/singleton.h to have |Singleton<|.
3493 black_list = (_EXCLUDED_PATHS +
3494 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043495 (r"^base[\\/]memory[\\/]singleton\.h$",
3496 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473497 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433498 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3499
sergeyu34d21222015-09-16 00:11:443500 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433501 files = []
3502 for f in input_api.AffectedSourceFiles(FileFilter):
3503 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3504 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3505 contents = input_api.ReadFile(f)
3506 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243507 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433508 pattern.search(line)):
3509 files.append(f)
3510 break
3511
3512 if files:
yolandyandaabc6d2016-04-18 18:29:393513 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443514 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433515 'Please move them to an appropriate source file so that the ' +
3516 'template gets instantiated in a single compilation unit.',
3517 files) ]
3518 return []
3519
3520
[email protected]fd20b902014-05-09 02:14:533521_DEPRECATED_CSS = [
3522 # Values
3523 ( "-webkit-box", "flex" ),
3524 ( "-webkit-inline-box", "inline-flex" ),
3525 ( "-webkit-flex", "flex" ),
3526 ( "-webkit-inline-flex", "inline-flex" ),
3527 ( "-webkit-min-content", "min-content" ),
3528 ( "-webkit-max-content", "max-content" ),
3529
3530 # Properties
3531 ( "-webkit-background-clip", "background-clip" ),
3532 ( "-webkit-background-origin", "background-origin" ),
3533 ( "-webkit-background-size", "background-size" ),
3534 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443535 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533536
3537 # Functions
3538 ( "-webkit-gradient", "gradient" ),
3539 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3540 ( "-webkit-linear-gradient", "linear-gradient" ),
3541 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3542 ( "-webkit-radial-gradient", "radial-gradient" ),
3543 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3544]
3545
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203546
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493547# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243548def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533549 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253550 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343551 documentation and iOS CSS for dom distiller
3552 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253553 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533554 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493555 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253556 black_list = (_EXCLUDED_PATHS +
3557 _TEST_CODE_EXCLUDED_PATHS +
3558 input_api.DEFAULT_BLACK_LIST +
3559 (r"^chrome/common/extensions/docs",
3560 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343561 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443562 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253563 r"^native_client_sdk"))
3564 file_filter = lambda f: input_api.FilterSourceFile(
3565 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533566 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3567 for line_num, line in fpath.ChangedContents():
3568 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023569 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533570 results.append(output_api.PresubmitError(
3571 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3572 (fpath.LocalPath(), line_num, deprecated_value, value)))
3573 return results
3574
mohan.reddyf21db962014-10-16 12:26:473575
rlanday6802cf632017-05-30 17:48:363576def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363577 bad_files = {}
3578 for f in input_api.AffectedFiles(include_deletes=False):
3579 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493580 not f.LocalPath().startswith('third_party/blink') and
3581 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363582 continue
3583
Daniel Bratell65b033262019-04-23 08:17:063584 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363585 continue
3586
Vaclav Brozekd5de76a2018-03-17 07:57:503587 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363588 if "#include" in line and "../" in line]
3589 if not relative_includes:
3590 continue
3591 bad_files[f.LocalPath()] = relative_includes
3592
3593 if not bad_files:
3594 return []
3595
3596 error_descriptions = []
3597 for file_path, bad_lines in bad_files.iteritems():
3598 error_description = file_path
3599 for line in bad_lines:
3600 error_description += '\n ' + line
3601 error_descriptions.append(error_description)
3602
3603 results = []
3604 results.append(output_api.PresubmitError(
3605 'You added one or more relative #include paths (including "../").\n'
3606 'These shouldn\'t be used because they can be used to include headers\n'
3607 'from code that\'s not correctly specified as a dependency in the\n'
3608 'relevant BUILD.gn file(s).',
3609 error_descriptions))
3610
3611 return results
3612
Takeshi Yoshinoe387aa32017-08-02 13:16:133613
Daniel Bratell65b033262019-04-23 08:17:063614def _CheckForCcIncludes(input_api, output_api):
3615 """Check that nobody tries to include a cc file. It's a relatively
3616 common error which results in duplicate symbols in object
3617 files. This may not always break the build until someone later gets
3618 very confusing linking errors."""
3619 results = []
3620 for f in input_api.AffectedFiles(include_deletes=False):
3621 # We let third_party code do whatever it wants
3622 if (f.LocalPath().startswith('third_party') and
3623 not f.LocalPath().startswith('third_party/blink') and
3624 not f.LocalPath().startswith('third_party\\blink')):
3625 continue
3626
3627 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3628 continue
3629
3630 for _, line in f.ChangedContents():
3631 if line.startswith('#include "'):
3632 included_file = line.split('"')[1]
3633 if _IsCPlusPlusFile(input_api, included_file):
3634 # The most common naming for external files with C++ code,
3635 # apart from standard headers, is to call them foo.inc, but
3636 # Chromium sometimes uses foo-inc.cc so allow that as well.
3637 if not included_file.endswith(('.h', '-inc.cc')):
3638 results.append(output_api.PresubmitError(
3639 'Only header files or .inc files should be included in other\n'
3640 'C++ files. Compiling the contents of a cc file more than once\n'
3641 'will cause duplicate information in the build which may later\n'
3642 'result in strange link_errors.\n' +
3643 f.LocalPath() + ':\n ' +
3644 line))
3645
3646 return results
3647
3648
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203649def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3650 if not isinstance(key, ast.Str):
3651 return 'Key at line %d must be a string literal' % key.lineno
3652 if not isinstance(value, ast.Dict):
3653 return 'Value at line %d must be a dict' % value.lineno
3654 if len(value.keys) != 1:
3655 return 'Dict at line %d must have single entry' % value.lineno
3656 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3657 return (
3658 'Entry at line %d must have a string literal \'filepath\' as key' %
3659 value.lineno)
3660 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133661
Takeshi Yoshinoe387aa32017-08-02 13:16:133662
Sergey Ulanov4af16052018-11-08 02:41:463663def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203664 if not isinstance(key, ast.Str):
3665 return 'Key at line %d must be a string literal' % key.lineno
3666 if not isinstance(value, ast.List):
3667 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463668 for element in value.elts:
3669 if not isinstance(element, ast.Str):
3670 return 'Watchlist elements on line %d is not a string' % key.lineno
3671 if not email_regex.match(element.s):
3672 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3673 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203674 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133675
Takeshi Yoshinoe387aa32017-08-02 13:16:133676
Sergey Ulanov4af16052018-11-08 02:41:463677def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203678 mismatch_template = (
3679 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3680 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133681
Sergey Ulanov4af16052018-11-08 02:41:463682 email_regex = input_api.re.compile(
3683 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3684
3685 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203686 i = 0
3687 last_key = ''
3688 while True:
3689 if i >= len(wd_dict.keys):
3690 if i >= len(w_dict.keys):
3691 return None
3692 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3693 elif i >= len(w_dict.keys):
3694 return (
3695 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133696
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203697 wd_key = wd_dict.keys[i]
3698 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133699
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203700 result = _CheckWatchlistDefinitionsEntrySyntax(
3701 wd_key, wd_dict.values[i], ast)
3702 if result is not None:
3703 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133704
Sergey Ulanov4af16052018-11-08 02:41:463705 result = _CheckWatchlistsEntrySyntax(
3706 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203707 if result is not None:
3708 return 'Bad entry in WATCHLISTS dict: %s' % result
3709
3710 if wd_key.s != w_key.s:
3711 return mismatch_template % (
3712 '%s at line %d' % (wd_key.s, wd_key.lineno),
3713 '%s at line %d' % (w_key.s, w_key.lineno))
3714
3715 if wd_key.s < last_key:
3716 return (
3717 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3718 (wd_key.lineno, w_key.lineno))
3719 last_key = wd_key.s
3720
3721 i = i + 1
3722
3723
Sergey Ulanov4af16052018-11-08 02:41:463724def _CheckWATCHLISTSSyntax(expression, input_api):
3725 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203726 if not isinstance(expression, ast.Expression):
3727 return 'WATCHLISTS file must contain a valid expression'
3728 dictionary = expression.body
3729 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3730 return 'WATCHLISTS file must have single dict with exactly two entries'
3731
3732 first_key = dictionary.keys[0]
3733 first_value = dictionary.values[0]
3734 second_key = dictionary.keys[1]
3735 second_value = dictionary.values[1]
3736
3737 if (not isinstance(first_key, ast.Str) or
3738 first_key.s != 'WATCHLIST_DEFINITIONS' or
3739 not isinstance(first_value, ast.Dict)):
3740 return (
3741 'The first entry of the dict in WATCHLISTS file must be '
3742 'WATCHLIST_DEFINITIONS dict')
3743
3744 if (not isinstance(second_key, ast.Str) or
3745 second_key.s != 'WATCHLISTS' or
3746 not isinstance(second_value, ast.Dict)):
3747 return (
3748 'The second entry of the dict in WATCHLISTS file must be '
3749 'WATCHLISTS dict')
3750
Sergey Ulanov4af16052018-11-08 02:41:463751 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133752
3753
3754def _CheckWATCHLISTS(input_api, output_api):
3755 for f in input_api.AffectedFiles(include_deletes=False):
3756 if f.LocalPath() == 'WATCHLISTS':
3757 contents = input_api.ReadFile(f, 'r')
3758
3759 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203760 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133761 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203762 # Get an AST tree for it and scan the tree for detailed style checking.
3763 expression = input_api.ast.parse(
3764 contents, filename='WATCHLISTS', mode='eval')
3765 except ValueError as e:
3766 return [output_api.PresubmitError(
3767 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3768 except SyntaxError as e:
3769 return [output_api.PresubmitError(
3770 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3771 except TypeError as e:
3772 return [output_api.PresubmitError(
3773 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133774
Sergey Ulanov4af16052018-11-08 02:41:463775 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203776 if result is not None:
3777 return [output_api.PresubmitError(result)]
3778 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133779
3780 return []
3781
3782
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193783def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3784 """Checks that newly added header files have corresponding GN changes.
3785 Note that this is only a heuristic. To be precise, run script:
3786 build/check_gn_headers.py.
3787 """
3788
3789 def headers(f):
3790 return input_api.FilterSourceFile(
3791 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3792
3793 new_headers = []
3794 for f in input_api.AffectedSourceFiles(headers):
3795 if f.Action() != 'A':
3796 continue
3797 new_headers.append(f.LocalPath())
3798
3799 def gn_files(f):
3800 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3801
3802 all_gn_changed_contents = ''
3803 for f in input_api.AffectedSourceFiles(gn_files):
3804 for _, line in f.ChangedContents():
3805 all_gn_changed_contents += line
3806
3807 problems = []
3808 for header in new_headers:
3809 basename = input_api.os_path.basename(header)
3810 if basename not in all_gn_changed_contents:
3811 problems.append(header)
3812
3813 if problems:
3814 return [output_api.PresubmitPromptWarning(
3815 'Missing GN changes for new header files', items=sorted(problems),
3816 long_text='Please double check whether newly added header files need '
3817 'corresponding changes in gn or gni files.\nThis checking is only a '
3818 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3819 'Read https://crbug.com/661774 for more info.')]
3820 return []
3821
3822
Michael Giuffridad3bc8672018-10-25 22:48:023823def _CheckCorrectProductNameInMessages(input_api, output_api):
3824 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3825
3826 This assumes we won't intentionally reference one product from the other
3827 product.
3828 """
3829 all_problems = []
3830 test_cases = [{
3831 "filename_postfix": "google_chrome_strings.grd",
3832 "correct_name": "Chrome",
3833 "incorrect_name": "Chromium",
3834 }, {
3835 "filename_postfix": "chromium_strings.grd",
3836 "correct_name": "Chromium",
3837 "incorrect_name": "Chrome",
3838 }]
3839
3840 for test_case in test_cases:
3841 problems = []
3842 filename_filter = lambda x: x.LocalPath().endswith(
3843 test_case["filename_postfix"])
3844
3845 # Check each new line. Can yield false positives in multiline comments, but
3846 # easier than trying to parse the XML because messages can have nested
3847 # children, and associating message elements with affected lines is hard.
3848 for f in input_api.AffectedSourceFiles(filename_filter):
3849 for line_num, line in f.ChangedContents():
3850 if "<message" in line or "<!--" in line or "-->" in line:
3851 continue
3852 if test_case["incorrect_name"] in line:
3853 problems.append(
3854 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3855
3856 if problems:
3857 message = (
3858 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3859 % (test_case["correct_name"], test_case["correct_name"],
3860 test_case["incorrect_name"]))
3861 all_problems.append(
3862 output_api.PresubmitPromptWarning(message, items=problems))
3863
3864 return all_problems
3865
3866
Dirk Pranke3c18a382019-03-15 01:07:513867def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3868 # TODO(crbug.com/941824): We need to make sure the entries in
3869 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3870 # so that users of //buildtools in other projects get the same tooling
3871 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3872 # support to gclient, we can eliminate the duplication and delete
3873 # this presubmit check.
3874
3875 # Update this regexp if new revisions are added to the files.
3876 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013877 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513878
3879 # If a user is changing one revision, they need to change the same
3880 # line in both files. This means that any given change should contain
3881 # exactly the same list of changed lines that match the regexps. The
3882 # replace(' ', '') call allows us to ignore whitespace changes to the
3883 # lines. The 'long_text' parameter to the error will contain the
3884 # list of changed lines in both files, which should make it easy enough
3885 # to spot the error without going overboard in this implementation.
3886 revs_changes = {
3887 'DEPS': {},
3888 'buildtools/DEPS': {},
3889 }
3890 long_text = ''
3891
3892 for f in input_api.AffectedFiles(
3893 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3894 for line_num, line in f.ChangedContents():
3895 if rev_regexp.search(line):
3896 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3897 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3898
3899 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3900 return [output_api.PresubmitError(
3901 'Change buildtools revisions in sync in both //DEPS and '
3902 '//buildtools/DEPS.', long_text=long_text + '\n')]
3903 else:
3904 return []
3905
3906
Daniel Bratell93eb6c62019-04-29 20:13:363907def _CheckForTooLargeFiles(input_api, output_api):
3908 """Avoid large files, especially binary files, in the repository since
3909 git doesn't scale well for those. They will be in everyone's repo
3910 clones forever, forever making Chromium slower to clone and work
3911 with."""
3912
3913 # Uploading files to cloud storage is not trivial so we don't want
3914 # to set the limit too low, but the upper limit for "normal" large
3915 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3916 # anything over 20 MB is exceptional.
3917 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3918
3919 too_large_files = []
3920 for f in input_api.AffectedFiles():
3921 # Check both added and modified files (but not deleted files).
3922 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383923 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363924 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3925 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3926
3927 if too_large_files:
3928 message = (
3929 'Do not commit large files to git since git scales badly for those.\n' +
3930 'Instead put the large files in cloud storage and use DEPS to\n' +
3931 'fetch them.\n' + '\n'.join(too_large_files)
3932 )
3933 return [output_api.PresubmitError(
3934 'Too large files found in commit', long_text=message + '\n')]
3935 else:
3936 return []
3937
Max Morozb47503b2019-08-08 21:03:273938
3939def _CheckFuzzTargets(input_api, output_api):
3940 """Checks specific for fuzz target sources."""
3941 EXPORTED_SYMBOLS = [
3942 'LLVMFuzzerInitialize',
3943 'LLVMFuzzerCustomMutator',
3944 'LLVMFuzzerCustomCrossOver',
3945 'LLVMFuzzerMutate',
3946 ]
3947
3948 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3949
3950 def FilterFile(affected_file):
3951 """Ignore libFuzzer source code."""
3952 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
3953 black_list = r"^third_party[\\/]libFuzzer"
3954
3955 return input_api.FilterSourceFile(
3956 affected_file,
3957 white_list=[white_list],
3958 black_list=[black_list])
3959
3960 files_with_missing_header = []
3961 for f in input_api.AffectedSourceFiles(FilterFile):
3962 contents = input_api.ReadFile(f, 'r')
3963 if REQUIRED_HEADER in contents:
3964 continue
3965
3966 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
3967 files_with_missing_header.append(f.LocalPath())
3968
3969 if not files_with_missing_header:
3970 return []
3971
3972 long_text = (
3973 'If you define any of the libFuzzer optional functions (%s), it is '
3974 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
3975 'work incorrectly on Mac (crbug.com/687076).\nNote that '
3976 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
3977 'to access command line arguments passed to the fuzzer. Instead, prefer '
3978 'static initialization and shared resources as documented in '
3979 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
3980 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
3981 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
3982 )
3983
3984 return [output_api.PresubmitPromptWarning(
3985 message="Missing '%s' in:" % REQUIRED_HEADER,
3986 items=files_with_missing_header,
3987 long_text=long_text)]
3988
3989
dgnaa68d5e2015-06-10 10:08:223990def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573991 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223992 results = []
dgnaa68d5e2015-06-10 10:08:223993 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173994 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223995 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293996 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063997 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3998 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423999 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184000 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574001 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4002 return results
4003
4004def _AndroidSpecificOnCommitChecks(input_api, output_api):
4005 """Groups commit checks that target android code."""
4006 results = []
4007 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224008 return results
4009
4010
[email protected]22c9bd72011-03-27 16:47:394011def _CommonChecks(input_api, output_api):
4012 """Checks common to both upload and commit."""
4013 results = []
4014 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384015 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544016 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084017
4018 author = input_api.change.author_email
4019 if author and author not in _KNOWN_ROBOTS:
4020 results.extend(
4021 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4022
[email protected]55459852011-08-10 15:17:194023 results.extend(
[email protected]760deea2013-12-10 19:33:494024 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234025 results.extend(
4026 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544027 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184028 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344029 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524030 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224031 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444032 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594033 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314034 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064035 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124036 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184037 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224038 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304039 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494040 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034041 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494042 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444043 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274044 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074045 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544046 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444047 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394048 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554049 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044050 results.extend(
4051 input_api.canned_checks.CheckChangeHasNoTabs(
4052 input_api,
4053 output_api,
4054 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404055 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164056 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084057 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244058 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474059 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044060 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054061 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144062 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234063 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434064 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404065 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154066 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:174067 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504068 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364069 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064070 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134071 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434072 results.extend(input_api.RunTests(
4073 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144074 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024075 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514076 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364077 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004078 results.extend(_CheckPythonDevilInit(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244079
Vaclav Brozekcdc7defb2018-03-20 09:54:354080 for f in input_api.AffectedFiles():
4081 path, name = input_api.os_path.split(f.LocalPath())
4082 if name == 'PRESUBMIT.py':
4083 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004084 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4085 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074086 # The PRESUBMIT.py file (and the directory containing it) might
4087 # have been affected by being moved or removed, so only try to
4088 # run the tests if they still exist.
4089 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4090 input_api, output_api, full_path,
4091 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394092 return results
[email protected]1f7b4172010-01-28 01:17:344093
[email protected]b337cb5b2011-01-23 21:24:054094
[email protected]b8079ae4a2012-12-05 19:56:494095def _CheckPatchFiles(input_api, output_api):
4096 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4097 if f.LocalPath().endswith(('.orig', '.rej'))]
4098 if problems:
4099 return [output_api.PresubmitError(
4100 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034101 else:
4102 return []
[email protected]b8079ae4a2012-12-05 19:56:494103
4104
Kent Tamura5a8755d2017-06-29 23:37:074105def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214106 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4107 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4108 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074109 include_re = input_api.re.compile(
4110 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4111 extension_re = input_api.re.compile(r'\.[a-z]+$')
4112 errors = []
4113 for f in input_api.AffectedFiles():
4114 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4115 continue
4116 found_line_number = None
4117 found_macro = None
4118 for line_num, line in f.ChangedContents():
4119 match = macro_re.search(line)
4120 if match:
4121 found_line_number = line_num
4122 found_macro = match.group(2)
4123 break
4124 if not found_line_number:
4125 continue
4126
4127 found_include = False
4128 for line in f.NewContents():
4129 if include_re.search(line):
4130 found_include = True
4131 break
4132 if found_include:
4133 continue
4134
4135 if not f.LocalPath().endswith('.h'):
4136 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4137 try:
4138 content = input_api.ReadFile(primary_header_path, 'r')
4139 if include_re.search(content):
4140 continue
4141 except IOError:
4142 pass
4143 errors.append('%s:%d %s macro is used without including build/'
4144 'build_config.h.'
4145 % (f.LocalPath(), found_line_number, found_macro))
4146 if errors:
4147 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4148 return []
4149
4150
[email protected]b00342e7f2013-03-26 16:21:544151def _DidYouMeanOSMacro(bad_macro):
4152 try:
4153 return {'A': 'OS_ANDROID',
4154 'B': 'OS_BSD',
4155 'C': 'OS_CHROMEOS',
4156 'F': 'OS_FREEBSD',
4157 'L': 'OS_LINUX',
4158 'M': 'OS_MACOSX',
4159 'N': 'OS_NACL',
4160 'O': 'OS_OPENBSD',
4161 'P': 'OS_POSIX',
4162 'S': 'OS_SOLARIS',
4163 'W': 'OS_WIN'}[bad_macro[3].upper()]
4164 except KeyError:
4165 return ''
4166
4167
4168def _CheckForInvalidOSMacrosInFile(input_api, f):
4169 """Check for sensible looking, totally invalid OS macros."""
4170 preprocessor_statement = input_api.re.compile(r'^\s*#')
4171 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4172 results = []
4173 for lnum, line in f.ChangedContents():
4174 if preprocessor_statement.search(line):
4175 for match in os_macro.finditer(line):
4176 if not match.group(1) in _VALID_OS_MACROS:
4177 good = _DidYouMeanOSMacro(match.group(1))
4178 did_you_mean = ' (did you mean %s?)' % good if good else ''
4179 results.append(' %s:%d %s%s' % (f.LocalPath(),
4180 lnum,
4181 match.group(1),
4182 did_you_mean))
4183 return results
4184
4185
4186def _CheckForInvalidOSMacros(input_api, output_api):
4187 """Check all affected files for invalid OS macros."""
4188 bad_macros = []
tzik3f295992018-12-04 20:32:234189 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474190 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544191 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4192
4193 if not bad_macros:
4194 return []
4195
4196 return [output_api.PresubmitError(
4197 'Possibly invalid OS macro[s] found. Please fix your code\n'
4198 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4199
lliabraa35bab3932014-10-01 12:16:444200
4201def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4202 """Check all affected files for invalid "if defined" macros."""
4203 ALWAYS_DEFINED_MACROS = (
4204 "TARGET_CPU_PPC",
4205 "TARGET_CPU_PPC64",
4206 "TARGET_CPU_68K",
4207 "TARGET_CPU_X86",
4208 "TARGET_CPU_ARM",
4209 "TARGET_CPU_MIPS",
4210 "TARGET_CPU_SPARC",
4211 "TARGET_CPU_ALPHA",
4212 "TARGET_IPHONE_SIMULATOR",
4213 "TARGET_OS_EMBEDDED",
4214 "TARGET_OS_IPHONE",
4215 "TARGET_OS_MAC",
4216 "TARGET_OS_UNIX",
4217 "TARGET_OS_WIN32",
4218 )
4219 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4220 results = []
4221 for lnum, line in f.ChangedContents():
4222 for match in ifdef_macro.finditer(line):
4223 if match.group(1) in ALWAYS_DEFINED_MACROS:
4224 always_defined = ' %s is always defined. ' % match.group(1)
4225 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4226 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4227 lnum,
4228 always_defined,
4229 did_you_mean))
4230 return results
4231
4232
4233def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4234 """Check all affected files for invalid "if defined" macros."""
4235 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054236 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444237 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054238 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214239 continue
lliabraa35bab3932014-10-01 12:16:444240 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4241 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4242
4243 if not bad_macros:
4244 return []
4245
4246 return [output_api.PresubmitError(
4247 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4248 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4249 bad_macros)]
4250
4251
mlamouria82272622014-09-16 18:45:044252def _CheckForIPCRules(input_api, output_api):
4253 """Check for same IPC rules described in
4254 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4255 """
4256 base_pattern = r'IPC_ENUM_TRAITS\('
4257 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4258 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4259
4260 problems = []
4261 for f in input_api.AffectedSourceFiles(None):
4262 local_path = f.LocalPath()
4263 if not local_path.endswith('.h'):
4264 continue
4265 for line_number, line in f.ChangedContents():
4266 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4267 problems.append(
4268 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4269
4270 if problems:
4271 return [output_api.PresubmitPromptWarning(
4272 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4273 else:
4274 return []
4275
[email protected]b00342e7f2013-03-26 16:21:544276
Stephen Martinis97a394142018-06-07 23:06:054277def _CheckForLongPathnames(input_api, output_api):
4278 """Check to make sure no files being submitted have long paths.
4279 This causes issues on Windows.
4280 """
4281 problems = []
4282 for f in input_api.AffectedSourceFiles(None):
4283 local_path = f.LocalPath()
4284 # Windows has a path limit of 260 characters. Limit path length to 200 so
4285 # that we have some extra for the prefix on dev machines and the bots.
4286 if len(local_path) > 200:
4287 problems.append(local_path)
4288
4289 if problems:
4290 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4291 else:
4292 return []
4293
4294
Daniel Bratell8ba52722018-03-02 16:06:144295def _CheckForIncludeGuards(input_api, output_api):
4296 """Check that header files have proper guards against multiple inclusion.
4297 If a file should not have such guards (and it probably should) then it
4298 should include the string "no-include-guard-because-multiply-included".
4299 """
Daniel Bratell6a75baef62018-06-04 10:04:454300 def is_chromium_header_file(f):
4301 # We only check header files under the control of the Chromium
4302 # project. That is, those outside third_party apart from
4303 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324304 # We also exclude *_message_generator.h headers as they use
4305 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454306 file_with_path = input_api.os_path.normpath(f.LocalPath())
4307 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324308 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454309 (not file_with_path.startswith('third_party') or
4310 file_with_path.startswith(
4311 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144312
4313 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344314 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144315
4316 errors = []
4317
Daniel Bratell6a75baef62018-06-04 10:04:454318 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144319 guard_name = None
4320 guard_line_number = None
4321 seen_guard_end = False
4322
4323 file_with_path = input_api.os_path.normpath(f.LocalPath())
4324 base_file_name = input_api.os_path.splitext(
4325 input_api.os_path.basename(file_with_path))[0]
4326 upper_base_file_name = base_file_name.upper()
4327
4328 expected_guard = replace_special_with_underscore(
4329 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144330
4331 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574332 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4333 # are too many (1000+) files with slight deviations from the
4334 # coding style. The most important part is that the include guard
4335 # is there, and that it's unique, not the name so this check is
4336 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144337 #
4338 # As code becomes more uniform, this could be made stricter.
4339
4340 guard_name_pattern_list = [
4341 # Anything with the right suffix (maybe with an extra _).
4342 r'\w+_H__?',
4343
Daniel Bratell39b5b062018-05-16 18:09:574344 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144345 r'\w+_h',
4346
4347 # Anything including the uppercase name of the file.
4348 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4349 upper_base_file_name)) + r'\w*',
4350 ]
4351 guard_name_pattern = '|'.join(guard_name_pattern_list)
4352 guard_pattern = input_api.re.compile(
4353 r'#ifndef\s+(' + guard_name_pattern + ')')
4354
4355 for line_number, line in enumerate(f.NewContents()):
4356 if 'no-include-guard-because-multiply-included' in line:
4357 guard_name = 'DUMMY' # To not trigger check outside the loop.
4358 break
4359
4360 if guard_name is None:
4361 match = guard_pattern.match(line)
4362 if match:
4363 guard_name = match.group(1)
4364 guard_line_number = line_number
4365
Daniel Bratell39b5b062018-05-16 18:09:574366 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454367 # don't match the chromium style guide, but new files should
4368 # get it right.
4369 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574370 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144371 errors.append(output_api.PresubmitPromptWarning(
4372 'Header using the wrong include guard name %s' % guard_name,
4373 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:574374 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144375 else:
4376 # The line after #ifndef should have a #define of the same name.
4377 if line_number == guard_line_number + 1:
4378 expected_line = '#define %s' % guard_name
4379 if line != expected_line:
4380 errors.append(output_api.PresubmitPromptWarning(
4381 'Missing "%s" for include guard' % expected_line,
4382 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4383 'Expected: %r\nGot: %r' % (expected_line, line)))
4384
4385 if not seen_guard_end and line == '#endif // %s' % guard_name:
4386 seen_guard_end = True
4387 elif seen_guard_end:
4388 if line.strip() != '':
4389 errors.append(output_api.PresubmitPromptWarning(
4390 'Include guard %s not covering the whole file' % (
4391 guard_name), [f.LocalPath()]))
4392 break # Nothing else to check and enough to warn once.
4393
4394 if guard_name is None:
4395 errors.append(output_api.PresubmitPromptWarning(
4396 'Missing include guard %s' % expected_guard,
4397 [f.LocalPath()],
4398 'Missing include guard in %s\n'
4399 'Recommended name: %s\n'
4400 'This check can be disabled by having the string\n'
4401 'no-include-guard-because-multiply-included in the header.' %
4402 (f.LocalPath(), expected_guard)))
4403
4404 return errors
4405
4406
mostynbb639aca52015-01-07 20:31:234407def _CheckForWindowsLineEndings(input_api, output_api):
4408 """Check source code and known ascii text files for Windows style line
4409 endings.
4410 """
earthdok1b5e0ee2015-03-10 15:19:104411 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234412
4413 file_inclusion_pattern = (
4414 known_text_files,
4415 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4416 )
4417
mostynbb639aca52015-01-07 20:31:234418 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534419 source_file_filter = lambda f: input_api.FilterSourceFile(
4420 f, white_list=file_inclusion_pattern, black_list=None)
4421 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504422 include_file = False
4423 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234424 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504425 include_file = True
4426 if include_file:
4427 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234428
4429 if problems:
4430 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4431 'these files to contain Windows style line endings?\n' +
4432 '\n'.join(problems))]
4433
4434 return []
4435
4436
Vaclav Brozekd5de76a2018-03-17 07:57:504437def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134438 """Checks that all source files use SYSLOG properly."""
4439 syslog_files = []
4440 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564441 for line_number, line in f.ChangedContents():
4442 if 'SYSLOG' in line:
4443 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4444
pastarmovj89f7ee12016-09-20 14:58:134445 if syslog_files:
4446 return [output_api.PresubmitPromptWarning(
4447 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4448 ' calls.\nFiles to check:\n', items=syslog_files)]
4449 return []
4450
4451
[email protected]1f7b4172010-01-28 01:17:344452def CheckChangeOnUpload(input_api, output_api):
4453 results = []
4454 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474455 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284456 results.extend(
jam93a6ee792017-02-08 23:59:224457 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194458 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224459 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134460 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164461 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534462 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194463 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274464 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544465 return results
[email protected]ca8d1982009-02-19 16:33:124466
4467
[email protected]1bfb8322014-04-23 01:02:414468def GetTryServerMasterForBot(bot):
4469 """Returns the Try Server master for the given bot.
4470
[email protected]0bb112362014-07-26 04:38:324471 It tries to guess the master from the bot name, but may still fail
4472 and return None. There is no longer a default master.
4473 """
4474 # Potentially ambiguous bot names are listed explicitly.
4475 master_map = {
tandriie5587792016-07-14 00:34:504476 'chromium_presubmit': 'master.tryserver.chromium.linux',
4477 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414478 }
[email protected]0bb112362014-07-26 04:38:324479 master = master_map.get(bot)
4480 if not master:
wnwen4fbaab82016-05-25 12:54:364481 if 'android' in bot:
tandriie5587792016-07-14 00:34:504482 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364483 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504484 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324485 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504486 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324487 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504488 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324489 return master
[email protected]1bfb8322014-04-23 01:02:414490
4491
[email protected]ca8d1982009-02-19 16:33:124492def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544493 results = []
[email protected]1f7b4172010-01-28 01:17:344494 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574495 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544496 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274497 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344498 input_api,
4499 output_api,
[email protected]2fdd1f362013-01-16 03:56:034500 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274501
jam93a6ee792017-02-08 23:59:224502 results.extend(
4503 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544504 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4505 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414506 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4507 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544508 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144509
4510
4511def _CheckTranslationScreenshots(input_api, output_api):
4512 PART_FILE_TAG = "part"
4513 import os
4514 import sys
4515 from io import StringIO
4516
4517 try:
4518 old_sys_path = sys.path
4519 sys.path = sys.path + [input_api.os_path.join(
4520 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4521 import grit.grd_reader
4522 import grit.node.message
4523 import grit.util
4524 finally:
4525 sys.path = old_sys_path
4526
4527 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4528 """Load the grd file and return a dict of message ids to messages.
4529
4530 Ignores any nested grdp files pointed by <part> tag.
4531 """
4532 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4533 stop_after=None, first_ids_file=None,
Julian Pastarmov4f7af532019-07-17 19:25:374534 debug=False, defines={'_chromium': 1},
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144535 tags_to_ignore=set([PART_FILE_TAG]))
4536 return {
4537 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4538 grit.node.message.MessageNode)
4539 }
4540
4541 def _GetGrdpMessagesFromString(grdp_string):
4542 """Parses the contents of a grdp file given in grdp_string.
4543
4544 grd_reader can't parse grdp files directly. Instead, this creates a
4545 temporary directory with a grd file pointing to the grdp file, and loads the
4546 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4547 """
4548 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4549 <grit latest_public_release="1" current_release="1">
4550 <release seq="1">
4551 <messages>
4552 <part file="sub.grdp" />
4553 </messages>
4554 </release>
4555 </grit>
4556 """
4557 with grit.util.TempDir({'main.grd': WRAPPER,
4558 'sub.grdp': grdp_string}) as temp_dir:
4559 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4560
4561 new_or_added_paths = set(f.LocalPath()
4562 for f in input_api.AffectedFiles()
4563 if (f.Action() == 'A' or f.Action() == 'M'))
4564 removed_paths = set(f.LocalPath()
4565 for f in input_api.AffectedFiles(include_deletes=True)
4566 if f.Action() == 'D')
4567
4568 affected_grds = [f for f in input_api.AffectedFiles()
4569 if (f.LocalPath().endswith('.grd') or
4570 f.LocalPath().endswith('.grdp'))]
4571 affected_png_paths = [f.AbsoluteLocalPath()
4572 for f in input_api.AffectedFiles()
4573 if (f.LocalPath().endswith('.png'))]
4574
4575 # Check for screenshots. Developers can upload screenshots using
4576 # tools/translation/upload_screenshots.py which finds and uploads
4577 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4578 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4579 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4580 #
4581 # The logic here is as follows:
4582 #
4583 # - If the CL has a .png file under the screenshots directory for a grd
4584 # file, warn the developer. Actual images should never be checked into the
4585 # Chrome repo.
4586 #
4587 # - If the CL contains modified or new messages in grd files and doesn't
4588 # contain the corresponding .sha1 files, warn the developer to add images
4589 # and upload them via tools/translation/upload_screenshots.py.
4590 #
4591 # - If the CL contains modified or new messages in grd files and the
4592 # corresponding .sha1 files, everything looks good.
4593 #
4594 # - If the CL contains removed messages in grd files but the corresponding
4595 # .sha1 files aren't removed, warn the developer to remove them.
4596 unnecessary_screenshots = []
4597 missing_sha1 = []
4598 unnecessary_sha1_files = []
4599
4600
4601 def _CheckScreenshotAdded(screenshots_dir, message_id):
4602 sha1_path = input_api.os_path.join(
4603 screenshots_dir, message_id + '.png.sha1')
4604 if sha1_path not in new_or_added_paths:
4605 missing_sha1.append(sha1_path)
4606
4607
4608 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4609 sha1_path = input_api.os_path.join(
4610 screenshots_dir, message_id + '.png.sha1')
4611 if sha1_path not in removed_paths:
4612 unnecessary_sha1_files.append(sha1_path)
4613
4614
4615 for f in affected_grds:
4616 file_path = f.LocalPath()
4617 old_id_to_msg_map = {}
4618 new_id_to_msg_map = {}
4619 if file_path.endswith('.grdp'):
4620 if f.OldContents():
4621 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394622 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144623 if f.NewContents():
4624 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394625 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144626 else:
4627 if f.OldContents():
4628 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394629 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144630 if f.NewContents():
4631 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394632 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144633
4634 # Compute added, removed and modified message IDs.
4635 old_ids = set(old_id_to_msg_map)
4636 new_ids = set(new_id_to_msg_map)
4637 added_ids = new_ids - old_ids
4638 removed_ids = old_ids - new_ids
4639 modified_ids = set([])
4640 for key in old_ids.intersection(new_ids):
4641 if (old_id_to_msg_map[key].FormatXml()
4642 != new_id_to_msg_map[key].FormatXml()):
4643 modified_ids.add(key)
4644
4645 grd_name, ext = input_api.os_path.splitext(
4646 input_api.os_path.basename(file_path))
4647 screenshots_dir = input_api.os_path.join(
4648 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4649
4650 # Check the screenshot directory for .png files. Warn if there is any.
4651 for png_path in affected_png_paths:
4652 if png_path.startswith(screenshots_dir):
4653 unnecessary_screenshots.append(png_path)
4654
4655 for added_id in added_ids:
4656 _CheckScreenshotAdded(screenshots_dir, added_id)
4657
4658 for modified_id in modified_ids:
4659 _CheckScreenshotAdded(screenshots_dir, modified_id)
4660
4661 for removed_id in removed_ids:
4662 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4663
4664 results = []
4665 if unnecessary_screenshots:
4666 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394667 'Do not include actual screenshots in the changelist. Run '
4668 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144669 sorted(unnecessary_screenshots)))
4670
4671 if missing_sha1:
4672 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394673 'You are adding or modifying UI strings.\n'
4674 'To ensure the best translations, take screenshots of the relevant UI '
4675 '(https://g.co/chrome/translation) and add these files to your '
4676 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144677
4678 if unnecessary_sha1_files:
4679 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394680 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144681 sorted(unnecessary_sha1_files)))
4682
4683 return results