blob: e92f01fc05a2aa785e07f05f6dea9ae9afb8c6ae [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
Bo Liubfde1c02019-09-24 23:08:353310 android.webview.ValueCallback except in the WebView glue layer
3311 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183312 """
3313 valuecallback_import_pattern = input_api.re.compile(
3314 r'^import android\.webkit\.ValueCallback;$')
3315
3316 errors = []
3317
3318 sources = lambda affected_file: input_api.FilterSourceFile(
3319 affected_file,
3320 black_list=(_EXCLUDED_PATHS +
3321 _TEST_CODE_EXCLUDED_PATHS +
3322 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353323 (r'^android_webview[\\/]glue[\\/].*',
3324 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493325 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183326
3327 for f in input_api.AffectedSourceFiles(sources):
3328 for line_num, line in f.ChangedContents():
3329 if valuecallback_import_pattern.search(line):
3330 errors.append("%s:%d" % (f.LocalPath(), line_num))
3331
3332 results = []
3333
3334 if errors:
3335 results.append(output_api.PresubmitError(
3336 'android.webkit.ValueCallback usage is detected outside of the glue'
3337 ' layer. To stay compatible with the support library, android.webkit.*'
3338 ' classes should only be used inside the glue layer and'
3339 ' org.chromium.base.Callback should be used instead.',
3340 errors))
3341
3342 return results
3343
3344
Becky Zhou7c69b50992018-12-10 19:37:573345def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3346 """Checks Android XML styles """
3347 import sys
3348 original_sys_path = sys.path
3349 try:
3350 sys.path = sys.path + [input_api.os_path.join(
3351 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3352 import checkxmlstyle
3353 finally:
3354 # Restore sys.path to what it was before.
3355 sys.path = original_sys_path
3356
3357 if is_check_on_upload:
3358 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3359 else:
3360 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3361
3362
agrievef32bcc72016-04-04 14:57:403363class PydepsChecker(object):
3364 def __init__(self, input_api, pydeps_files):
3365 self._file_cache = {}
3366 self._input_api = input_api
3367 self._pydeps_files = pydeps_files
3368
3369 def _LoadFile(self, path):
3370 """Returns the list of paths within a .pydeps file relative to //."""
3371 if path not in self._file_cache:
3372 with open(path) as f:
3373 self._file_cache[path] = f.read()
3374 return self._file_cache[path]
3375
3376 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3377 """Returns an interable of paths within the .pydep, relativized to //."""
3378 os_path = self._input_api.os_path
3379 pydeps_dir = os_path.dirname(pydeps_path)
3380 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3381 if not l.startswith('*'))
3382 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3383
3384 def _CreateFilesToPydepsMap(self):
3385 """Returns a map of local_path -> list_of_pydeps."""
3386 ret = {}
3387 for pydep_local_path in self._pydeps_files:
3388 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3389 ret.setdefault(path, []).append(pydep_local_path)
3390 return ret
3391
3392 def ComputeAffectedPydeps(self):
3393 """Returns an iterable of .pydeps files that might need regenerating."""
3394 affected_pydeps = set()
3395 file_to_pydeps_map = None
3396 for f in self._input_api.AffectedFiles(include_deletes=True):
3397 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463398 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3399 # subrepositories. We can't figure out which files change, so re-check
3400 # all files.
3401 # Changes to print_python_deps.py affect all .pydeps.
3402 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403403 return self._pydeps_files
3404 elif local_path.endswith('.pydeps'):
3405 if local_path in self._pydeps_files:
3406 affected_pydeps.add(local_path)
3407 elif local_path.endswith('.py'):
3408 if file_to_pydeps_map is None:
3409 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3410 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3411 return affected_pydeps
3412
3413 def DetermineIfStale(self, pydeps_path):
3414 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413415 import difflib
John Budorick47ca3fe2018-02-10 00:53:103416 import os
3417
agrievef32bcc72016-04-04 14:57:403418 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3419 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103420 env = dict(os.environ)
3421 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403422 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103423 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413424 old_contents = old_pydeps_data[2:]
3425 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403426 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413427 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403428
3429
Tibor Goldschwendt360793f72019-06-25 18:23:493430def _ParseGclientArgs():
3431 args = {}
3432 with open('build/config/gclient_args.gni', 'r') as f:
3433 for line in f:
3434 line = line.strip()
3435 if not line or line.startswith('#'):
3436 continue
3437 attribute, value = line.split('=')
3438 args[attribute.strip()] = value.strip()
3439 return args
3440
3441
agrievef32bcc72016-04-04 14:57:403442def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3443 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403444 # This check is for Python dependency lists (.pydeps files), and involves
3445 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3446 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283447 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003448 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493449 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403450 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3451 results = []
3452 # First, check for new / deleted .pydeps.
3453 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033454 # Check whether we are running the presubmit check for a file in src.
3455 # f.LocalPath is relative to repo (src, or internal repo).
3456 # os_path.exists is relative to src repo.
3457 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3458 # to src and we can conclude that the pydeps is in src.
3459 if input_api.os_path.exists(f.LocalPath()):
3460 if f.LocalPath().endswith('.pydeps'):
3461 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3462 results.append(output_api.PresubmitError(
3463 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3464 'remove %s' % f.LocalPath()))
3465 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3466 results.append(output_api.PresubmitError(
3467 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3468 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403469
3470 if results:
3471 return results
3472
3473 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3474
3475 for pydep_path in checker.ComputeAffectedPydeps():
3476 try:
phajdan.jr0d9878552016-11-04 10:49:413477 result = checker.DetermineIfStale(pydep_path)
3478 if result:
3479 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403480 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413481 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3482 'To regenerate, run:\n\n %s' %
3483 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403484 except input_api.subprocess.CalledProcessError as error:
3485 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3486 long_text=error.output)]
3487
3488 return results
3489
3490
glidere61efad2015-02-18 17:39:433491def _CheckSingletonInHeaders(input_api, output_api):
3492 """Checks to make sure no header files have |Singleton<|."""
3493 def FileFilter(affected_file):
3494 # It's ok for base/memory/singleton.h to have |Singleton<|.
3495 black_list = (_EXCLUDED_PATHS +
3496 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043497 (r"^base[\\/]memory[\\/]singleton\.h$",
3498 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473499 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433500 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3501
sergeyu34d21222015-09-16 00:11:443502 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433503 files = []
3504 for f in input_api.AffectedSourceFiles(FileFilter):
3505 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3506 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3507 contents = input_api.ReadFile(f)
3508 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243509 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433510 pattern.search(line)):
3511 files.append(f)
3512 break
3513
3514 if files:
yolandyandaabc6d2016-04-18 18:29:393515 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443516 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433517 'Please move them to an appropriate source file so that the ' +
3518 'template gets instantiated in a single compilation unit.',
3519 files) ]
3520 return []
3521
3522
[email protected]fd20b902014-05-09 02:14:533523_DEPRECATED_CSS = [
3524 # Values
3525 ( "-webkit-box", "flex" ),
3526 ( "-webkit-inline-box", "inline-flex" ),
3527 ( "-webkit-flex", "flex" ),
3528 ( "-webkit-inline-flex", "inline-flex" ),
3529 ( "-webkit-min-content", "min-content" ),
3530 ( "-webkit-max-content", "max-content" ),
3531
3532 # Properties
3533 ( "-webkit-background-clip", "background-clip" ),
3534 ( "-webkit-background-origin", "background-origin" ),
3535 ( "-webkit-background-size", "background-size" ),
3536 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443537 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533538
3539 # Functions
3540 ( "-webkit-gradient", "gradient" ),
3541 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3542 ( "-webkit-linear-gradient", "linear-gradient" ),
3543 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3544 ( "-webkit-radial-gradient", "radial-gradient" ),
3545 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3546]
3547
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203548
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493549# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243550def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533551 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253552 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343553 documentation and iOS CSS for dom distiller
3554 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253555 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533556 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493557 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253558 black_list = (_EXCLUDED_PATHS +
3559 _TEST_CODE_EXCLUDED_PATHS +
3560 input_api.DEFAULT_BLACK_LIST +
3561 (r"^chrome/common/extensions/docs",
3562 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343563 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443564 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253565 r"^native_client_sdk"))
3566 file_filter = lambda f: input_api.FilterSourceFile(
3567 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533568 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3569 for line_num, line in fpath.ChangedContents():
3570 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023571 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533572 results.append(output_api.PresubmitError(
3573 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3574 (fpath.LocalPath(), line_num, deprecated_value, value)))
3575 return results
3576
mohan.reddyf21db962014-10-16 12:26:473577
rlanday6802cf632017-05-30 17:48:363578def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363579 bad_files = {}
3580 for f in input_api.AffectedFiles(include_deletes=False):
3581 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493582 not f.LocalPath().startswith('third_party/blink') and
3583 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363584 continue
3585
Daniel Bratell65b033262019-04-23 08:17:063586 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363587 continue
3588
Vaclav Brozekd5de76a2018-03-17 07:57:503589 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363590 if "#include" in line and "../" in line]
3591 if not relative_includes:
3592 continue
3593 bad_files[f.LocalPath()] = relative_includes
3594
3595 if not bad_files:
3596 return []
3597
3598 error_descriptions = []
3599 for file_path, bad_lines in bad_files.iteritems():
3600 error_description = file_path
3601 for line in bad_lines:
3602 error_description += '\n ' + line
3603 error_descriptions.append(error_description)
3604
3605 results = []
3606 results.append(output_api.PresubmitError(
3607 'You added one or more relative #include paths (including "../").\n'
3608 'These shouldn\'t be used because they can be used to include headers\n'
3609 'from code that\'s not correctly specified as a dependency in the\n'
3610 'relevant BUILD.gn file(s).',
3611 error_descriptions))
3612
3613 return results
3614
Takeshi Yoshinoe387aa32017-08-02 13:16:133615
Daniel Bratell65b033262019-04-23 08:17:063616def _CheckForCcIncludes(input_api, output_api):
3617 """Check that nobody tries to include a cc file. It's a relatively
3618 common error which results in duplicate symbols in object
3619 files. This may not always break the build until someone later gets
3620 very confusing linking errors."""
3621 results = []
3622 for f in input_api.AffectedFiles(include_deletes=False):
3623 # We let third_party code do whatever it wants
3624 if (f.LocalPath().startswith('third_party') and
3625 not f.LocalPath().startswith('third_party/blink') and
3626 not f.LocalPath().startswith('third_party\\blink')):
3627 continue
3628
3629 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3630 continue
3631
3632 for _, line in f.ChangedContents():
3633 if line.startswith('#include "'):
3634 included_file = line.split('"')[1]
3635 if _IsCPlusPlusFile(input_api, included_file):
3636 # The most common naming for external files with C++ code,
3637 # apart from standard headers, is to call them foo.inc, but
3638 # Chromium sometimes uses foo-inc.cc so allow that as well.
3639 if not included_file.endswith(('.h', '-inc.cc')):
3640 results.append(output_api.PresubmitError(
3641 'Only header files or .inc files should be included in other\n'
3642 'C++ files. Compiling the contents of a cc file more than once\n'
3643 'will cause duplicate information in the build which may later\n'
3644 'result in strange link_errors.\n' +
3645 f.LocalPath() + ':\n ' +
3646 line))
3647
3648 return results
3649
3650
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203651def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3652 if not isinstance(key, ast.Str):
3653 return 'Key at line %d must be a string literal' % key.lineno
3654 if not isinstance(value, ast.Dict):
3655 return 'Value at line %d must be a dict' % value.lineno
3656 if len(value.keys) != 1:
3657 return 'Dict at line %d must have single entry' % value.lineno
3658 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3659 return (
3660 'Entry at line %d must have a string literal \'filepath\' as key' %
3661 value.lineno)
3662 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133663
Takeshi Yoshinoe387aa32017-08-02 13:16:133664
Sergey Ulanov4af16052018-11-08 02:41:463665def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203666 if not isinstance(key, ast.Str):
3667 return 'Key at line %d must be a string literal' % key.lineno
3668 if not isinstance(value, ast.List):
3669 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463670 for element in value.elts:
3671 if not isinstance(element, ast.Str):
3672 return 'Watchlist elements on line %d is not a string' % key.lineno
3673 if not email_regex.match(element.s):
3674 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3675 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203676 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133677
Takeshi Yoshinoe387aa32017-08-02 13:16:133678
Sergey Ulanov4af16052018-11-08 02:41:463679def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203680 mismatch_template = (
3681 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3682 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133683
Sergey Ulanov4af16052018-11-08 02:41:463684 email_regex = input_api.re.compile(
3685 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3686
3687 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203688 i = 0
3689 last_key = ''
3690 while True:
3691 if i >= len(wd_dict.keys):
3692 if i >= len(w_dict.keys):
3693 return None
3694 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3695 elif i >= len(w_dict.keys):
3696 return (
3697 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133698
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203699 wd_key = wd_dict.keys[i]
3700 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133701
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203702 result = _CheckWatchlistDefinitionsEntrySyntax(
3703 wd_key, wd_dict.values[i], ast)
3704 if result is not None:
3705 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133706
Sergey Ulanov4af16052018-11-08 02:41:463707 result = _CheckWatchlistsEntrySyntax(
3708 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203709 if result is not None:
3710 return 'Bad entry in WATCHLISTS dict: %s' % result
3711
3712 if wd_key.s != w_key.s:
3713 return mismatch_template % (
3714 '%s at line %d' % (wd_key.s, wd_key.lineno),
3715 '%s at line %d' % (w_key.s, w_key.lineno))
3716
3717 if wd_key.s < last_key:
3718 return (
3719 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3720 (wd_key.lineno, w_key.lineno))
3721 last_key = wd_key.s
3722
3723 i = i + 1
3724
3725
Sergey Ulanov4af16052018-11-08 02:41:463726def _CheckWATCHLISTSSyntax(expression, input_api):
3727 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203728 if not isinstance(expression, ast.Expression):
3729 return 'WATCHLISTS file must contain a valid expression'
3730 dictionary = expression.body
3731 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3732 return 'WATCHLISTS file must have single dict with exactly two entries'
3733
3734 first_key = dictionary.keys[0]
3735 first_value = dictionary.values[0]
3736 second_key = dictionary.keys[1]
3737 second_value = dictionary.values[1]
3738
3739 if (not isinstance(first_key, ast.Str) or
3740 first_key.s != 'WATCHLIST_DEFINITIONS' or
3741 not isinstance(first_value, ast.Dict)):
3742 return (
3743 'The first entry of the dict in WATCHLISTS file must be '
3744 'WATCHLIST_DEFINITIONS dict')
3745
3746 if (not isinstance(second_key, ast.Str) or
3747 second_key.s != 'WATCHLISTS' or
3748 not isinstance(second_value, ast.Dict)):
3749 return (
3750 'The second entry of the dict in WATCHLISTS file must be '
3751 'WATCHLISTS dict')
3752
Sergey Ulanov4af16052018-11-08 02:41:463753 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133754
3755
3756def _CheckWATCHLISTS(input_api, output_api):
3757 for f in input_api.AffectedFiles(include_deletes=False):
3758 if f.LocalPath() == 'WATCHLISTS':
3759 contents = input_api.ReadFile(f, 'r')
3760
3761 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203762 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133763 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203764 # Get an AST tree for it and scan the tree for detailed style checking.
3765 expression = input_api.ast.parse(
3766 contents, filename='WATCHLISTS', mode='eval')
3767 except ValueError as e:
3768 return [output_api.PresubmitError(
3769 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3770 except SyntaxError as e:
3771 return [output_api.PresubmitError(
3772 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3773 except TypeError as e:
3774 return [output_api.PresubmitError(
3775 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133776
Sergey Ulanov4af16052018-11-08 02:41:463777 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203778 if result is not None:
3779 return [output_api.PresubmitError(result)]
3780 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133781
3782 return []
3783
3784
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193785def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3786 """Checks that newly added header files have corresponding GN changes.
3787 Note that this is only a heuristic. To be precise, run script:
3788 build/check_gn_headers.py.
3789 """
3790
3791 def headers(f):
3792 return input_api.FilterSourceFile(
3793 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3794
3795 new_headers = []
3796 for f in input_api.AffectedSourceFiles(headers):
3797 if f.Action() != 'A':
3798 continue
3799 new_headers.append(f.LocalPath())
3800
3801 def gn_files(f):
3802 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3803
3804 all_gn_changed_contents = ''
3805 for f in input_api.AffectedSourceFiles(gn_files):
3806 for _, line in f.ChangedContents():
3807 all_gn_changed_contents += line
3808
3809 problems = []
3810 for header in new_headers:
3811 basename = input_api.os_path.basename(header)
3812 if basename not in all_gn_changed_contents:
3813 problems.append(header)
3814
3815 if problems:
3816 return [output_api.PresubmitPromptWarning(
3817 'Missing GN changes for new header files', items=sorted(problems),
3818 long_text='Please double check whether newly added header files need '
3819 'corresponding changes in gn or gni files.\nThis checking is only a '
3820 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3821 'Read https://crbug.com/661774 for more info.')]
3822 return []
3823
3824
Michael Giuffridad3bc8672018-10-25 22:48:023825def _CheckCorrectProductNameInMessages(input_api, output_api):
3826 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3827
3828 This assumes we won't intentionally reference one product from the other
3829 product.
3830 """
3831 all_problems = []
3832 test_cases = [{
3833 "filename_postfix": "google_chrome_strings.grd",
3834 "correct_name": "Chrome",
3835 "incorrect_name": "Chromium",
3836 }, {
3837 "filename_postfix": "chromium_strings.grd",
3838 "correct_name": "Chromium",
3839 "incorrect_name": "Chrome",
3840 }]
3841
3842 for test_case in test_cases:
3843 problems = []
3844 filename_filter = lambda x: x.LocalPath().endswith(
3845 test_case["filename_postfix"])
3846
3847 # Check each new line. Can yield false positives in multiline comments, but
3848 # easier than trying to parse the XML because messages can have nested
3849 # children, and associating message elements with affected lines is hard.
3850 for f in input_api.AffectedSourceFiles(filename_filter):
3851 for line_num, line in f.ChangedContents():
3852 if "<message" in line or "<!--" in line or "-->" in line:
3853 continue
3854 if test_case["incorrect_name"] in line:
3855 problems.append(
3856 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3857
3858 if problems:
3859 message = (
3860 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3861 % (test_case["correct_name"], test_case["correct_name"],
3862 test_case["incorrect_name"]))
3863 all_problems.append(
3864 output_api.PresubmitPromptWarning(message, items=problems))
3865
3866 return all_problems
3867
3868
Dirk Pranke3c18a382019-03-15 01:07:513869def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3870 # TODO(crbug.com/941824): We need to make sure the entries in
3871 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3872 # so that users of //buildtools in other projects get the same tooling
3873 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3874 # support to gclient, we can eliminate the duplication and delete
3875 # this presubmit check.
3876
3877 # Update this regexp if new revisions are added to the files.
3878 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013879 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513880
3881 # If a user is changing one revision, they need to change the same
3882 # line in both files. This means that any given change should contain
3883 # exactly the same list of changed lines that match the regexps. The
3884 # replace(' ', '') call allows us to ignore whitespace changes to the
3885 # lines. The 'long_text' parameter to the error will contain the
3886 # list of changed lines in both files, which should make it easy enough
3887 # to spot the error without going overboard in this implementation.
3888 revs_changes = {
3889 'DEPS': {},
3890 'buildtools/DEPS': {},
3891 }
3892 long_text = ''
3893
3894 for f in input_api.AffectedFiles(
3895 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3896 for line_num, line in f.ChangedContents():
3897 if rev_regexp.search(line):
3898 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3899 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3900
3901 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3902 return [output_api.PresubmitError(
3903 'Change buildtools revisions in sync in both //DEPS and '
3904 '//buildtools/DEPS.', long_text=long_text + '\n')]
3905 else:
3906 return []
3907
3908
Daniel Bratell93eb6c62019-04-29 20:13:363909def _CheckForTooLargeFiles(input_api, output_api):
3910 """Avoid large files, especially binary files, in the repository since
3911 git doesn't scale well for those. They will be in everyone's repo
3912 clones forever, forever making Chromium slower to clone and work
3913 with."""
3914
3915 # Uploading files to cloud storage is not trivial so we don't want
3916 # to set the limit too low, but the upper limit for "normal" large
3917 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3918 # anything over 20 MB is exceptional.
3919 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3920
3921 too_large_files = []
3922 for f in input_api.AffectedFiles():
3923 # Check both added and modified files (but not deleted files).
3924 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383925 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363926 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3927 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3928
3929 if too_large_files:
3930 message = (
3931 'Do not commit large files to git since git scales badly for those.\n' +
3932 'Instead put the large files in cloud storage and use DEPS to\n' +
3933 'fetch them.\n' + '\n'.join(too_large_files)
3934 )
3935 return [output_api.PresubmitError(
3936 'Too large files found in commit', long_text=message + '\n')]
3937 else:
3938 return []
3939
Max Morozb47503b2019-08-08 21:03:273940
3941def _CheckFuzzTargets(input_api, output_api):
3942 """Checks specific for fuzz target sources."""
3943 EXPORTED_SYMBOLS = [
3944 'LLVMFuzzerInitialize',
3945 'LLVMFuzzerCustomMutator',
3946 'LLVMFuzzerCustomCrossOver',
3947 'LLVMFuzzerMutate',
3948 ]
3949
3950 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3951
3952 def FilterFile(affected_file):
3953 """Ignore libFuzzer source code."""
3954 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
3955 black_list = r"^third_party[\\/]libFuzzer"
3956
3957 return input_api.FilterSourceFile(
3958 affected_file,
3959 white_list=[white_list],
3960 black_list=[black_list])
3961
3962 files_with_missing_header = []
3963 for f in input_api.AffectedSourceFiles(FilterFile):
3964 contents = input_api.ReadFile(f, 'r')
3965 if REQUIRED_HEADER in contents:
3966 continue
3967
3968 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
3969 files_with_missing_header.append(f.LocalPath())
3970
3971 if not files_with_missing_header:
3972 return []
3973
3974 long_text = (
3975 'If you define any of the libFuzzer optional functions (%s), it is '
3976 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
3977 'work incorrectly on Mac (crbug.com/687076).\nNote that '
3978 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
3979 'to access command line arguments passed to the fuzzer. Instead, prefer '
3980 'static initialization and shared resources as documented in '
3981 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
3982 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
3983 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
3984 )
3985
3986 return [output_api.PresubmitPromptWarning(
3987 message="Missing '%s' in:" % REQUIRED_HEADER,
3988 items=files_with_missing_header,
3989 long_text=long_text)]
3990
3991
dgnaa68d5e2015-06-10 10:08:223992def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573993 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223994 results = []
dgnaa68d5e2015-06-10 10:08:223995 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173996 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223997 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293998 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063999 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4000 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424001 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184002 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574003 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4004 return results
4005
4006def _AndroidSpecificOnCommitChecks(input_api, output_api):
4007 """Groups commit checks that target android code."""
4008 results = []
4009 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224010 return results
4011
4012
[email protected]22c9bd72011-03-27 16:47:394013def _CommonChecks(input_api, output_api):
4014 """Checks common to both upload and commit."""
4015 results = []
4016 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384017 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544018 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084019
4020 author = input_api.change.author_email
4021 if author and author not in _KNOWN_ROBOTS:
4022 results.extend(
4023 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4024
[email protected]55459852011-08-10 15:17:194025 results.extend(
[email protected]760deea2013-12-10 19:33:494026 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234027 results.extend(
4028 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544029 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184030 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344031 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524032 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224033 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444034 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594035 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314036 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064037 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124038 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184039 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224040 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304041 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494042 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034043 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494044 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444045 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274046 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074047 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544048 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444049 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394050 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554051 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044052 results.extend(
4053 input_api.canned_checks.CheckChangeHasNoTabs(
4054 input_api,
4055 output_api,
4056 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404057 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164058 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084059 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244060 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474061 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044062 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054063 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144064 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234065 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434066 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404067 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154068 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:174069 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504070 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364071 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064072 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134073 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434074 results.extend(input_api.RunTests(
4075 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144076 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024077 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514078 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364079 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004080 results.extend(_CheckPythonDevilInit(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244081
Vaclav Brozekcdc7defb2018-03-20 09:54:354082 for f in input_api.AffectedFiles():
4083 path, name = input_api.os_path.split(f.LocalPath())
4084 if name == 'PRESUBMIT.py':
4085 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004086 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4087 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074088 # The PRESUBMIT.py file (and the directory containing it) might
4089 # have been affected by being moved or removed, so only try to
4090 # run the tests if they still exist.
4091 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4092 input_api, output_api, full_path,
4093 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394094 return results
[email protected]1f7b4172010-01-28 01:17:344095
[email protected]b337cb5b2011-01-23 21:24:054096
[email protected]b8079ae4a2012-12-05 19:56:494097def _CheckPatchFiles(input_api, output_api):
4098 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4099 if f.LocalPath().endswith(('.orig', '.rej'))]
4100 if problems:
4101 return [output_api.PresubmitError(
4102 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034103 else:
4104 return []
[email protected]b8079ae4a2012-12-05 19:56:494105
4106
Kent Tamura5a8755d2017-06-29 23:37:074107def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214108 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4109 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4110 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074111 include_re = input_api.re.compile(
4112 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4113 extension_re = input_api.re.compile(r'\.[a-z]+$')
4114 errors = []
4115 for f in input_api.AffectedFiles():
4116 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4117 continue
4118 found_line_number = None
4119 found_macro = None
4120 for line_num, line in f.ChangedContents():
4121 match = macro_re.search(line)
4122 if match:
4123 found_line_number = line_num
4124 found_macro = match.group(2)
4125 break
4126 if not found_line_number:
4127 continue
4128
4129 found_include = False
4130 for line in f.NewContents():
4131 if include_re.search(line):
4132 found_include = True
4133 break
4134 if found_include:
4135 continue
4136
4137 if not f.LocalPath().endswith('.h'):
4138 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4139 try:
4140 content = input_api.ReadFile(primary_header_path, 'r')
4141 if include_re.search(content):
4142 continue
4143 except IOError:
4144 pass
4145 errors.append('%s:%d %s macro is used without including build/'
4146 'build_config.h.'
4147 % (f.LocalPath(), found_line_number, found_macro))
4148 if errors:
4149 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4150 return []
4151
4152
[email protected]b00342e7f2013-03-26 16:21:544153def _DidYouMeanOSMacro(bad_macro):
4154 try:
4155 return {'A': 'OS_ANDROID',
4156 'B': 'OS_BSD',
4157 'C': 'OS_CHROMEOS',
4158 'F': 'OS_FREEBSD',
4159 'L': 'OS_LINUX',
4160 'M': 'OS_MACOSX',
4161 'N': 'OS_NACL',
4162 'O': 'OS_OPENBSD',
4163 'P': 'OS_POSIX',
4164 'S': 'OS_SOLARIS',
4165 'W': 'OS_WIN'}[bad_macro[3].upper()]
4166 except KeyError:
4167 return ''
4168
4169
4170def _CheckForInvalidOSMacrosInFile(input_api, f):
4171 """Check for sensible looking, totally invalid OS macros."""
4172 preprocessor_statement = input_api.re.compile(r'^\s*#')
4173 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4174 results = []
4175 for lnum, line in f.ChangedContents():
4176 if preprocessor_statement.search(line):
4177 for match in os_macro.finditer(line):
4178 if not match.group(1) in _VALID_OS_MACROS:
4179 good = _DidYouMeanOSMacro(match.group(1))
4180 did_you_mean = ' (did you mean %s?)' % good if good else ''
4181 results.append(' %s:%d %s%s' % (f.LocalPath(),
4182 lnum,
4183 match.group(1),
4184 did_you_mean))
4185 return results
4186
4187
4188def _CheckForInvalidOSMacros(input_api, output_api):
4189 """Check all affected files for invalid OS macros."""
4190 bad_macros = []
tzik3f295992018-12-04 20:32:234191 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474192 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544193 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4194
4195 if not bad_macros:
4196 return []
4197
4198 return [output_api.PresubmitError(
4199 'Possibly invalid OS macro[s] found. Please fix your code\n'
4200 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4201
lliabraa35bab3932014-10-01 12:16:444202
4203def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4204 """Check all affected files for invalid "if defined" macros."""
4205 ALWAYS_DEFINED_MACROS = (
4206 "TARGET_CPU_PPC",
4207 "TARGET_CPU_PPC64",
4208 "TARGET_CPU_68K",
4209 "TARGET_CPU_X86",
4210 "TARGET_CPU_ARM",
4211 "TARGET_CPU_MIPS",
4212 "TARGET_CPU_SPARC",
4213 "TARGET_CPU_ALPHA",
4214 "TARGET_IPHONE_SIMULATOR",
4215 "TARGET_OS_EMBEDDED",
4216 "TARGET_OS_IPHONE",
4217 "TARGET_OS_MAC",
4218 "TARGET_OS_UNIX",
4219 "TARGET_OS_WIN32",
4220 )
4221 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4222 results = []
4223 for lnum, line in f.ChangedContents():
4224 for match in ifdef_macro.finditer(line):
4225 if match.group(1) in ALWAYS_DEFINED_MACROS:
4226 always_defined = ' %s is always defined. ' % match.group(1)
4227 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4228 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4229 lnum,
4230 always_defined,
4231 did_you_mean))
4232 return results
4233
4234
4235def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4236 """Check all affected files for invalid "if defined" macros."""
4237 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054238 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444239 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054240 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214241 continue
lliabraa35bab3932014-10-01 12:16:444242 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4243 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4244
4245 if not bad_macros:
4246 return []
4247
4248 return [output_api.PresubmitError(
4249 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4250 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4251 bad_macros)]
4252
4253
mlamouria82272622014-09-16 18:45:044254def _CheckForIPCRules(input_api, output_api):
4255 """Check for same IPC rules described in
4256 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4257 """
4258 base_pattern = r'IPC_ENUM_TRAITS\('
4259 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4260 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4261
4262 problems = []
4263 for f in input_api.AffectedSourceFiles(None):
4264 local_path = f.LocalPath()
4265 if not local_path.endswith('.h'):
4266 continue
4267 for line_number, line in f.ChangedContents():
4268 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4269 problems.append(
4270 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4271
4272 if problems:
4273 return [output_api.PresubmitPromptWarning(
4274 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4275 else:
4276 return []
4277
[email protected]b00342e7f2013-03-26 16:21:544278
Stephen Martinis97a394142018-06-07 23:06:054279def _CheckForLongPathnames(input_api, output_api):
4280 """Check to make sure no files being submitted have long paths.
4281 This causes issues on Windows.
4282 """
4283 problems = []
4284 for f in input_api.AffectedSourceFiles(None):
4285 local_path = f.LocalPath()
4286 # Windows has a path limit of 260 characters. Limit path length to 200 so
4287 # that we have some extra for the prefix on dev machines and the bots.
4288 if len(local_path) > 200:
4289 problems.append(local_path)
4290
4291 if problems:
4292 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4293 else:
4294 return []
4295
4296
Daniel Bratell8ba52722018-03-02 16:06:144297def _CheckForIncludeGuards(input_api, output_api):
4298 """Check that header files have proper guards against multiple inclusion.
4299 If a file should not have such guards (and it probably should) then it
4300 should include the string "no-include-guard-because-multiply-included".
4301 """
Daniel Bratell6a75baef62018-06-04 10:04:454302 def is_chromium_header_file(f):
4303 # We only check header files under the control of the Chromium
4304 # project. That is, those outside third_party apart from
4305 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324306 # We also exclude *_message_generator.h headers as they use
4307 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454308 file_with_path = input_api.os_path.normpath(f.LocalPath())
4309 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324310 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454311 (not file_with_path.startswith('third_party') or
4312 file_with_path.startswith(
4313 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144314
4315 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344316 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144317
4318 errors = []
4319
Daniel Bratell6a75baef62018-06-04 10:04:454320 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144321 guard_name = None
4322 guard_line_number = None
4323 seen_guard_end = False
4324
4325 file_with_path = input_api.os_path.normpath(f.LocalPath())
4326 base_file_name = input_api.os_path.splitext(
4327 input_api.os_path.basename(file_with_path))[0]
4328 upper_base_file_name = base_file_name.upper()
4329
4330 expected_guard = replace_special_with_underscore(
4331 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144332
4333 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574334 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4335 # are too many (1000+) files with slight deviations from the
4336 # coding style. The most important part is that the include guard
4337 # is there, and that it's unique, not the name so this check is
4338 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144339 #
4340 # As code becomes more uniform, this could be made stricter.
4341
4342 guard_name_pattern_list = [
4343 # Anything with the right suffix (maybe with an extra _).
4344 r'\w+_H__?',
4345
Daniel Bratell39b5b062018-05-16 18:09:574346 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144347 r'\w+_h',
4348
4349 # Anything including the uppercase name of the file.
4350 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4351 upper_base_file_name)) + r'\w*',
4352 ]
4353 guard_name_pattern = '|'.join(guard_name_pattern_list)
4354 guard_pattern = input_api.re.compile(
4355 r'#ifndef\s+(' + guard_name_pattern + ')')
4356
4357 for line_number, line in enumerate(f.NewContents()):
4358 if 'no-include-guard-because-multiply-included' in line:
4359 guard_name = 'DUMMY' # To not trigger check outside the loop.
4360 break
4361
4362 if guard_name is None:
4363 match = guard_pattern.match(line)
4364 if match:
4365 guard_name = match.group(1)
4366 guard_line_number = line_number
4367
Daniel Bratell39b5b062018-05-16 18:09:574368 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454369 # don't match the chromium style guide, but new files should
4370 # get it right.
4371 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574372 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144373 errors.append(output_api.PresubmitPromptWarning(
4374 'Header using the wrong include guard name %s' % guard_name,
4375 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:574376 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144377 else:
4378 # The line after #ifndef should have a #define of the same name.
4379 if line_number == guard_line_number + 1:
4380 expected_line = '#define %s' % guard_name
4381 if line != expected_line:
4382 errors.append(output_api.PresubmitPromptWarning(
4383 'Missing "%s" for include guard' % expected_line,
4384 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4385 'Expected: %r\nGot: %r' % (expected_line, line)))
4386
4387 if not seen_guard_end and line == '#endif // %s' % guard_name:
4388 seen_guard_end = True
4389 elif seen_guard_end:
4390 if line.strip() != '':
4391 errors.append(output_api.PresubmitPromptWarning(
4392 'Include guard %s not covering the whole file' % (
4393 guard_name), [f.LocalPath()]))
4394 break # Nothing else to check and enough to warn once.
4395
4396 if guard_name is None:
4397 errors.append(output_api.PresubmitPromptWarning(
4398 'Missing include guard %s' % expected_guard,
4399 [f.LocalPath()],
4400 'Missing include guard in %s\n'
4401 'Recommended name: %s\n'
4402 'This check can be disabled by having the string\n'
4403 'no-include-guard-because-multiply-included in the header.' %
4404 (f.LocalPath(), expected_guard)))
4405
4406 return errors
4407
4408
mostynbb639aca52015-01-07 20:31:234409def _CheckForWindowsLineEndings(input_api, output_api):
4410 """Check source code and known ascii text files for Windows style line
4411 endings.
4412 """
earthdok1b5e0ee2015-03-10 15:19:104413 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234414
4415 file_inclusion_pattern = (
4416 known_text_files,
4417 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4418 )
4419
mostynbb639aca52015-01-07 20:31:234420 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534421 source_file_filter = lambda f: input_api.FilterSourceFile(
4422 f, white_list=file_inclusion_pattern, black_list=None)
4423 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504424 include_file = False
4425 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234426 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504427 include_file = True
4428 if include_file:
4429 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234430
4431 if problems:
4432 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4433 'these files to contain Windows style line endings?\n' +
4434 '\n'.join(problems))]
4435
4436 return []
4437
4438
Vaclav Brozekd5de76a2018-03-17 07:57:504439def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134440 """Checks that all source files use SYSLOG properly."""
4441 syslog_files = []
4442 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564443 for line_number, line in f.ChangedContents():
4444 if 'SYSLOG' in line:
4445 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4446
pastarmovj89f7ee12016-09-20 14:58:134447 if syslog_files:
4448 return [output_api.PresubmitPromptWarning(
4449 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4450 ' calls.\nFiles to check:\n', items=syslog_files)]
4451 return []
4452
4453
[email protected]1f7b4172010-01-28 01:17:344454def CheckChangeOnUpload(input_api, output_api):
4455 results = []
4456 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474457 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284458 results.extend(
jam93a6ee792017-02-08 23:59:224459 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194460 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224461 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134462 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164463 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534464 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194465 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274466 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544467 return results
[email protected]ca8d1982009-02-19 16:33:124468
4469
[email protected]1bfb8322014-04-23 01:02:414470def GetTryServerMasterForBot(bot):
4471 """Returns the Try Server master for the given bot.
4472
[email protected]0bb112362014-07-26 04:38:324473 It tries to guess the master from the bot name, but may still fail
4474 and return None. There is no longer a default master.
4475 """
4476 # Potentially ambiguous bot names are listed explicitly.
4477 master_map = {
tandriie5587792016-07-14 00:34:504478 'chromium_presubmit': 'master.tryserver.chromium.linux',
4479 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414480 }
[email protected]0bb112362014-07-26 04:38:324481 master = master_map.get(bot)
4482 if not master:
wnwen4fbaab82016-05-25 12:54:364483 if 'android' in bot:
tandriie5587792016-07-14 00:34:504484 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364485 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504486 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324487 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504488 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324489 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504490 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324491 return master
[email protected]1bfb8322014-04-23 01:02:414492
4493
[email protected]ca8d1982009-02-19 16:33:124494def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544495 results = []
[email protected]1f7b4172010-01-28 01:17:344496 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574497 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544498 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274499 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344500 input_api,
4501 output_api,
[email protected]2fdd1f362013-01-16 03:56:034502 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274503
jam93a6ee792017-02-08 23:59:224504 results.extend(
4505 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544506 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4507 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414508 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4509 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544510 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144511
4512
4513def _CheckTranslationScreenshots(input_api, output_api):
4514 PART_FILE_TAG = "part"
4515 import os
4516 import sys
4517 from io import StringIO
4518
4519 try:
4520 old_sys_path = sys.path
4521 sys.path = sys.path + [input_api.os_path.join(
4522 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4523 import grit.grd_reader
4524 import grit.node.message
4525 import grit.util
4526 finally:
4527 sys.path = old_sys_path
4528
4529 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4530 """Load the grd file and return a dict of message ids to messages.
4531
4532 Ignores any nested grdp files pointed by <part> tag.
4533 """
4534 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4535 stop_after=None, first_ids_file=None,
Julian Pastarmov4f7af532019-07-17 19:25:374536 debug=False, defines={'_chromium': 1},
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144537 tags_to_ignore=set([PART_FILE_TAG]))
4538 return {
4539 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4540 grit.node.message.MessageNode)
4541 }
4542
4543 def _GetGrdpMessagesFromString(grdp_string):
4544 """Parses the contents of a grdp file given in grdp_string.
4545
4546 grd_reader can't parse grdp files directly. Instead, this creates a
4547 temporary directory with a grd file pointing to the grdp file, and loads the
4548 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4549 """
4550 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4551 <grit latest_public_release="1" current_release="1">
4552 <release seq="1">
4553 <messages>
4554 <part file="sub.grdp" />
4555 </messages>
4556 </release>
4557 </grit>
4558 """
4559 with grit.util.TempDir({'main.grd': WRAPPER,
4560 'sub.grdp': grdp_string}) as temp_dir:
4561 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4562
4563 new_or_added_paths = set(f.LocalPath()
4564 for f in input_api.AffectedFiles()
4565 if (f.Action() == 'A' or f.Action() == 'M'))
4566 removed_paths = set(f.LocalPath()
4567 for f in input_api.AffectedFiles(include_deletes=True)
4568 if f.Action() == 'D')
4569
4570 affected_grds = [f for f in input_api.AffectedFiles()
4571 if (f.LocalPath().endswith('.grd') or
4572 f.LocalPath().endswith('.grdp'))]
4573 affected_png_paths = [f.AbsoluteLocalPath()
4574 for f in input_api.AffectedFiles()
4575 if (f.LocalPath().endswith('.png'))]
4576
4577 # Check for screenshots. Developers can upload screenshots using
4578 # tools/translation/upload_screenshots.py which finds and uploads
4579 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4580 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4581 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4582 #
4583 # The logic here is as follows:
4584 #
4585 # - If the CL has a .png file under the screenshots directory for a grd
4586 # file, warn the developer. Actual images should never be checked into the
4587 # Chrome repo.
4588 #
4589 # - If the CL contains modified or new messages in grd files and doesn't
4590 # contain the corresponding .sha1 files, warn the developer to add images
4591 # and upload them via tools/translation/upload_screenshots.py.
4592 #
4593 # - If the CL contains modified or new messages in grd files and the
4594 # corresponding .sha1 files, everything looks good.
4595 #
4596 # - If the CL contains removed messages in grd files but the corresponding
4597 # .sha1 files aren't removed, warn the developer to remove them.
4598 unnecessary_screenshots = []
4599 missing_sha1 = []
4600 unnecessary_sha1_files = []
4601
4602
4603 def _CheckScreenshotAdded(screenshots_dir, message_id):
4604 sha1_path = input_api.os_path.join(
4605 screenshots_dir, message_id + '.png.sha1')
4606 if sha1_path not in new_or_added_paths:
4607 missing_sha1.append(sha1_path)
4608
4609
4610 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4611 sha1_path = input_api.os_path.join(
4612 screenshots_dir, message_id + '.png.sha1')
4613 if sha1_path not in removed_paths:
4614 unnecessary_sha1_files.append(sha1_path)
4615
4616
4617 for f in affected_grds:
4618 file_path = f.LocalPath()
4619 old_id_to_msg_map = {}
4620 new_id_to_msg_map = {}
4621 if file_path.endswith('.grdp'):
4622 if f.OldContents():
4623 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394624 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144625 if f.NewContents():
4626 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394627 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144628 else:
4629 if f.OldContents():
4630 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394631 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144632 if f.NewContents():
4633 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394634 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144635
4636 # Compute added, removed and modified message IDs.
4637 old_ids = set(old_id_to_msg_map)
4638 new_ids = set(new_id_to_msg_map)
4639 added_ids = new_ids - old_ids
4640 removed_ids = old_ids - new_ids
4641 modified_ids = set([])
4642 for key in old_ids.intersection(new_ids):
4643 if (old_id_to_msg_map[key].FormatXml()
4644 != new_id_to_msg_map[key].FormatXml()):
4645 modified_ids.add(key)
4646
4647 grd_name, ext = input_api.os_path.splitext(
4648 input_api.os_path.basename(file_path))
4649 screenshots_dir = input_api.os_path.join(
4650 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4651
4652 # Check the screenshot directory for .png files. Warn if there is any.
4653 for png_path in affected_png_paths:
4654 if png_path.startswith(screenshots_dir):
4655 unnecessary_screenshots.append(png_path)
4656
4657 for added_id in added_ids:
4658 _CheckScreenshotAdded(screenshots_dir, added_id)
4659
4660 for modified_id in modified_ids:
4661 _CheckScreenshotAdded(screenshots_dir, modified_id)
4662
4663 for removed_id in removed_ids:
4664 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4665
4666 results = []
4667 if unnecessary_screenshots:
4668 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394669 'Do not include actual screenshots in the changelist. Run '
4670 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144671 sorted(unnecessary_screenshots)))
4672
4673 if missing_sha1:
4674 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394675 'You are adding or modifying UI strings.\n'
4676 'To ensure the best translations, take screenshots of the relevant UI '
4677 '(https://g.co/chrome/translation) and add these files to your '
4678 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144679
4680 if unnecessary_sha1_files:
4681 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394682 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144683 sorted(unnecessary_sha1_files)))
4684
4685 return results