blob: 8de4ce3eea9798d7d74e5aed65afe23cd0c06312 [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/',
danakj7a2b7082019-05-21 21:13:51383 '^components/webcrypto/',
384 '^components/webdata/',
385 '^components/webdata_services/',
386 '^components/wifi/',
387 '^components/zoom/',
388 '^content/app/',
389 '^content/browser/',
390 '^content/child/',
391 '^content/common/',
392 '^content/public/',
393 '^content/renderer/android/',
394 '^content/renderer/fetchers/',
395 '^content/renderer/image_downloader/',
396 '^content/renderer/input/',
397 '^content/renderer/java/',
398 '^content/renderer/media/',
399 '^content/renderer/media_capture_from_element/',
400 '^content/renderer/media_recorder/',
401 '^content/renderer/p2p/',
402 '^content/renderer/pepper/',
403 '^content/renderer/service_worker/',
404 '^content/renderer/worker/',
405 '^content/test/',
406 '^content/utility/',
407 '^dbus/',
408 '^device/base/',
409 '^device/bluetooth/',
410 '^device/fido/',
411 '^device/gamepad/',
danakj7a2b7082019-05-21 21:13:51412 '^device/vr/',
413 '^extensions/',
414 '^gin/',
415 '^google_apis/dive/',
416 '^google_apis/gaia/',
417 '^google_apis/gcm/',
418 '^headless/',
419 '^ios/chrome/',
420 '^ios/components/',
421 '^ios/net/',
422 '^ios/web/',
423 '^ios/web_view/',
424 '^ipc/',
425 '^media/audio/',
426 '^media/base/',
427 '^media/capture/',
428 '^media/cast/',
429 '^media/cdm/',
430 '^media/device_monitors/',
431 '^media/ffmpeg/',
432 '^media/filters/',
433 '^media/formats/',
434 '^media/gpu/',
435 '^media/mojo/',
436 '^media/muxers/',
437 '^media/remoting/',
438 '^media/renderers/',
439 '^media/test/',
440 '^mojo/core/',
441 '^mojo/public/',
442 '^net/',
443 '^ppapi/proxy/',
444 '^ppapi/shared_impl/',
445 '^ppapi/tests/',
446 '^ppapi/thunk/',
447 '^remoting/base/',
448 '^remoting/client/',
449 '^remoting/codec/',
450 '^remoting/host/',
451 '^remoting/internal/',
452 '^remoting/ios/',
453 '^remoting/protocol/',
454 '^remoting/signaling/',
455 '^remoting/test/',
456 '^sandbox/linux/',
457 '^sandbox/win/',
458 '^services/',
459 '^storage/browser/',
460 '^testing/gmock_mutant.h',
461 '^testing/libfuzzer/',
462 '^third_party/blink/',
463 '^third_party/crashpad/crashpad/test/gtest_main.cc',
464 '^third_party/leveldatabase/leveldb_chrome.cc',
465 '^third_party/boringssl/gtest_main_chromium.cc',
466 '^third_party/cacheinvalidation/overrides/' +
467 'google/cacheinvalidation/deps/callback.h',
468 '^third_party/libaddressinput/chromium/chrome_address_validator.cc',
469 '^third_party/zlib/google/',
470 '^tools/android/',
471 '^tools/clang/base_bind_rewriters/', # Intentional.
472 '^tools/gdb/gdb_chrome.py', # Intentional.
473 '^ui/accelerated_widget_mac/',
474 '^ui/android/',
475 '^ui/aura/',
476 '^ui/base/',
477 '^ui/compositor/',
478 '^ui/display/',
479 '^ui/events/',
480 '^ui/gfx/',
481 '^ui/message_center/',
danakj7a2b7082019-05-21 21:13:51482 '^ui/snapshot/',
483 '^ui/views_content_client/',
484 '^ui/wm/',
485))
[email protected]127f18ec2012-06-16 05:05:59486
Daniel Bratell609102be2019-03-27 20:53:21487# Format: Sequence of tuples containing:
488# * String pattern or, if starting with a slash, a regular expression.
489# * Sequence of strings to show when the pattern matches.
490# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
491# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59492_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20493 (
Dave Tapuska98199b612019-07-10 13:30:44494 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53495 (
496 'New code should not use NULL. Use nullptr instead.',
497 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20498 False,
thomasandersone7caaa9b2017-03-29 19:22:53499 (),
500 ),
Antonio Gomes07300d02019-03-13 20:59:57501 # Make sure that gtest's FRIEND_TEST() macro is not used; the
502 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
503 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53504 (
[email protected]23e6cbc2012-06-16 18:51:20505 'FRIEND_TEST(',
506 (
[email protected]e3c945502012-06-26 20:01:49507 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20508 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
509 ),
510 False,
[email protected]7345da02012-11-27 14:31:49511 (),
[email protected]23e6cbc2012-06-16 18:51:20512 ),
513 (
Dave Tapuska98199b612019-07-10 13:30:44514 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53515 (
516 'Chrome clients wishing to select events on X windows should use',
517 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
518 'you are selecting events from the GPU process, or if you are using',
519 'an XDisplay other than gfx::GetXDisplay().',
520 ),
521 True,
522 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40523 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04524 r"^ui[\\/]gl[\\/].*\.cc$",
525 r"^media[\\/]gpu[\\/].*\.cc$",
526 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53527 ),
528 ),
529 (
Dave Tapuska98199b612019-07-10 13:30:44530 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20531 (
thomasanderson11aa41d2017-06-08 22:22:38532 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20533 ),
534 True,
535 (
Egor Paskoce145c42018-09-28 19:31:04536 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
537 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
538 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20539 ),
540 ),
541 (
tomhudsone2c14d552016-05-26 17:07:46542 'setMatrixClip',
543 (
544 'Overriding setMatrixClip() is prohibited; ',
545 'the base function is deprecated. ',
546 ),
547 True,
548 (),
549 ),
550 (
[email protected]52657f62013-05-20 05:30:31551 'SkRefPtr',
552 (
553 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22554 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31555 ),
556 True,
557 (),
558 ),
559 (
560 'SkAutoRef',
561 (
562 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22563 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31564 ),
565 True,
566 (),
567 ),
568 (
569 'SkAutoTUnref',
570 (
571 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22572 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31573 ),
574 True,
575 (),
576 ),
577 (
578 'SkAutoUnref',
579 (
580 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
581 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22582 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31583 ),
584 True,
585 (),
586 ),
[email protected]d89eec82013-12-03 14:10:59587 (
588 r'/HANDLE_EINTR\(.*close',
589 (
590 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
591 'descriptor will be closed, and it is incorrect to retry the close.',
592 'Either call close directly and ignore its return value, or wrap close',
593 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
594 ),
595 True,
596 (),
597 ),
598 (
599 r'/IGNORE_EINTR\((?!.*close)',
600 (
601 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
602 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
603 ),
604 True,
605 (
606 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04607 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
608 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59609 ),
610 ),
[email protected]ec5b3f02014-04-04 18:43:43611 (
612 r'/v8::Extension\(',
613 (
614 'Do not introduce new v8::Extensions into the code base, use',
615 'gin::Wrappable instead. See http://crbug.com/334679',
616 ),
617 True,
[email protected]f55c90ee62014-04-12 00:50:03618 (
Egor Paskoce145c42018-09-28 19:31:04619 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03620 ),
[email protected]ec5b3f02014-04-04 18:43:43621 ),
skyostilf9469f72015-04-20 10:38:52622 (
jame2d1a952016-04-02 00:27:10623 '#pragma comment(lib,',
624 (
625 'Specify libraries to link with in build files and not in the source.',
626 ),
627 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41628 (
tzik3f295992018-12-04 20:32:23629 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04630 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41631 ),
jame2d1a952016-04-02 00:27:10632 ),
fdorayc4ac18d2017-05-01 21:39:59633 (
Gabriel Charette7cc6c432018-04-25 20:52:02634 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59635 (
636 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
637 ),
638 False,
639 (),
640 ),
641 (
Gabriel Charette7cc6c432018-04-25 20:52:02642 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59643 (
644 'Consider using THREAD_CHECKER macros instead of the class directly.',
645 ),
646 False,
647 (),
648 ),
dbeamb6f4fde2017-06-15 04:03:06649 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06650 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
651 (
652 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
653 'deprecated (http://crbug.com/634507). Please avoid converting away',
654 'from the Time types in Chromium code, especially if any math is',
655 'being done on time values. For interfacing with platform/library',
656 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
657 'type converter methods instead. For faking TimeXXX values (for unit',
658 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
659 'other use cases, please contact base/time/OWNERS.',
660 ),
661 False,
662 (),
663 ),
664 (
dbeamb6f4fde2017-06-15 04:03:06665 'CallJavascriptFunctionUnsafe',
666 (
667 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
668 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
669 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
670 ),
671 False,
672 (
Egor Paskoce145c42018-09-28 19:31:04673 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
674 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
675 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06676 ),
677 ),
dskiba1474c2bfd62017-07-20 02:19:24678 (
679 'leveldb::DB::Open',
680 (
681 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
682 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
683 "Chrome's tracing, making their memory usage visible.",
684 ),
685 True,
686 (
687 r'^third_party/leveldatabase/.*\.(cc|h)$',
688 ),
Gabriel Charette0592c3a2017-07-26 12:02:04689 ),
690 (
Chris Mumfordc38afb62017-10-09 17:55:08691 'leveldb::NewMemEnv',
692 (
693 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58694 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
695 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08696 ),
697 True,
698 (
699 r'^third_party/leveldatabase/.*\.(cc|h)$',
700 ),
701 ),
702 (
Gabriel Charetted9839bc2017-07-29 14:17:47703 'RunLoop::QuitCurrent',
704 (
Robert Liao64b7ab22017-08-04 23:03:43705 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
706 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47707 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41708 False,
Gabriel Charetted9839bc2017-07-29 14:17:47709 (),
Gabriel Charettea44975052017-08-21 23:14:04710 ),
711 (
712 'base::ScopedMockTimeMessageLoopTaskRunner',
713 (
Gabriel Charette87cc1af2018-04-25 20:52:51714 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11715 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51716 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
717 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
718 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04719 ),
Gabriel Charette87cc1af2018-04-25 20:52:51720 False,
Gabriel Charettea44975052017-08-21 23:14:04721 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57722 ),
723 (
Dave Tapuska98199b612019-07-10 13:30:44724 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57725 (
726 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02727 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57728 ),
729 True,
730 (),
Francois Doray43670e32017-09-27 12:40:38731 ),
732 (
Peter Kasting991618a62019-06-17 22:00:09733 r'/\bstd::stoi\b',
734 (
735 'std::stoi uses exceptions to communicate results. ',
736 'Use base::StringToInt() instead.',
737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
740 ),
741 (
742 r'/\bstd::stol\b',
743 (
744 'std::stol uses exceptions to communicate results. ',
745 'Use base::StringToInt() instead.',
746 ),
747 True,
748 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
749 ),
750 (
751 r'/\bstd::stoul\b',
752 (
753 'std::stoul uses exceptions to communicate results. ',
754 'Use base::StringToUint() instead.',
755 ),
756 True,
757 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
758 ),
759 (
760 r'/\bstd::stoll\b',
761 (
762 'std::stoll uses exceptions to communicate results. ',
763 'Use base::StringToInt64() instead.',
764 ),
765 True,
766 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
767 ),
768 (
769 r'/\bstd::stoull\b',
770 (
771 'std::stoull uses exceptions to communicate results. ',
772 'Use base::StringToUint64() instead.',
773 ),
774 True,
775 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
776 ),
777 (
778 r'/\bstd::stof\b',
779 (
780 'std::stof uses exceptions to communicate results. ',
781 'For locale-independent values, e.g. reading numbers from disk',
782 'profiles, use base::StringToDouble().',
783 'For user-visible values, parse using ICU.',
784 ),
785 True,
786 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
787 ),
788 (
789 r'/\bstd::stod\b',
790 (
791 'std::stod uses exceptions to communicate results. ',
792 'For locale-independent values, e.g. reading numbers from disk',
793 'profiles, use base::StringToDouble().',
794 'For user-visible values, parse using ICU.',
795 ),
796 True,
797 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
798 ),
799 (
800 r'/\bstd::stold\b',
801 (
802 'std::stold uses exceptions to communicate results. ',
803 'For locale-independent values, e.g. reading numbers from disk',
804 'profiles, use base::StringToDouble().',
805 'For user-visible values, parse using ICU.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
809 ),
810 (
Daniel Bratell69334cc2019-03-26 11:07:45811 r'/\bstd::to_string\b',
812 (
813 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09814 'For locale-independent strings, e.g. writing numbers to disk',
815 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45816 'For user-visible strings, use base::FormatNumber() and',
817 'the related functions in base/i18n/number_formatting.h.',
818 ),
Peter Kasting991618a62019-06-17 22:00:09819 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21820 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45821 ),
822 (
823 r'/\bstd::shared_ptr\b',
824 (
825 'std::shared_ptr should not be used. Use scoped_refptr instead.',
826 ),
827 True,
Daniel Bratell609102be2019-03-27 20:53:21828 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
829 ),
830 (
Peter Kasting991618a62019-06-17 22:00:09831 r'/\bstd::weak_ptr\b',
832 (
833 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
834 ),
835 True,
836 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
837 ),
838 (
Daniel Bratell609102be2019-03-27 20:53:21839 r'/\blong long\b',
840 (
841 'long long is banned. Use stdint.h if you need a 64 bit number.',
842 ),
843 False, # Only a warning since it is already used.
844 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
845 ),
846 (
847 r'/\bstd::bind\b',
848 (
849 'std::bind is banned because of lifetime risks.',
850 'Use base::BindOnce or base::BindRepeating instead.',
851 ),
852 True,
853 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
854 ),
855 (
856 r'/\b#include <chrono>\b',
857 (
858 '<chrono> overlaps with Time APIs in base. Keep using',
859 'base classes.',
860 ),
861 True,
862 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
863 ),
864 (
865 r'/\b#include <exception>\b',
866 (
867 'Exceptions are banned and disabled in Chromium.',
868 ),
869 True,
870 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
871 ),
872 (
873 r'/\bstd::function\b',
874 (
875 'std::function is banned. Instead use base::Callback which directly',
876 'supports Chromium\'s weak pointers, ref counting and more.',
877 ),
Peter Kasting991618a62019-06-17 22:00:09878 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21879 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
880 ),
881 (
882 r'/\b#include <random>\b',
883 (
884 'Do not use any random number engines from <random>. Instead',
885 'use base::RandomBitGenerator.',
886 ),
887 True,
888 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
889 ),
890 (
891 r'/\bstd::ratio\b',
892 (
893 'std::ratio is banned by the Google Style Guide.',
894 ),
895 True,
896 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45897 ),
898 (
Francois Doray43670e32017-09-27 12:40:38899 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
900 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
901 (
902 'Use the new API in base/threading/thread_restrictions.h.',
903 ),
Gabriel Charette04b138f2018-08-06 00:03:22904 False,
Francois Doray43670e32017-09-27 12:40:38905 (),
906 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38907 (
danakj7a2b7082019-05-21 21:13:51908 r'/\bbase::Bind\(',
909 (
910 'Please use base::Bind{Once,Repeating} instead',
911 'of base::Bind. (crbug.com/714018)',
912 ),
913 False,
914 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
915 ),
916 (
917 r'/\bbase::Callback[<:]',
918 (
919 'Please use base::{Once,Repeating}Callback instead',
920 'of base::Callback. (crbug.com/714018)',
921 ),
922 False,
923 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
924 ),
925 (
926 r'/\bbase::Closure\b',
927 (
928 'Please use base::{Once,Repeating}Closure instead',
929 'of base::Closure. (crbug.com/714018)',
930 ),
931 False,
932 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
933 ),
934 (
Alex Ilin5929abe32019-04-03 17:09:34935 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45936 (
937 'base::SharedMemory is deprecated. Please use',
938 '{Writable,ReadOnly}SharedMemoryRegion instead.',
939 ),
940 False,
941 (),
942 ),
943 (
Michael Giuffrida7f93d6922019-04-19 14:39:58944 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19945 (
946 'RunMessageLoop is deprecated, use RunLoop instead.',
947 ),
948 False,
949 (),
950 ),
951 (
Dave Tapuska98199b612019-07-10 13:30:44952 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19953 (
954 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
955 ),
956 False,
957 (),
958 ),
959 (
Dave Tapuska98199b612019-07-10 13:30:44960 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19961 (
962 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
963 "if you're convinced you need this.",
964 ),
965 False,
966 (),
967 ),
968 (
Dave Tapuska98199b612019-07-10 13:30:44969 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19970 (
971 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04972 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19973 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
974 'async events instead of flushing threads.',
975 ),
976 False,
977 (),
978 ),
979 (
980 r'MessageLoopRunner',
981 (
982 'MessageLoopRunner is deprecated, use RunLoop instead.',
983 ),
984 False,
985 (),
986 ),
987 (
Dave Tapuska98199b612019-07-10 13:30:44988 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19989 (
990 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
991 "gab@ if you found a use case where this is the only solution.",
992 ),
993 False,
994 (),
995 ),
996 (
Victor Costane48a2e82019-03-15 22:02:34997 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16998 (
Victor Costane48a2e82019-03-15 22:02:34999 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161000 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1001 ),
1002 True,
1003 (
1004 r'^sql/initialization\.(cc|h)$',
1005 r'^third_party/sqlite/.*\.(c|cc|h)$',
1006 ),
1007 ),
Matt Menke7f520a82018-03-28 21:38:371008 (
1009 'net::URLFetcher',
1010 (
1011 'net::URLFetcher should no longer be used in content embedders. ',
1012 'Instead, use network::SimpleURLLoader instead, which supports ',
1013 'an out-of-process network stack. ',
1014 'net::URLFetcher may still be used in binaries that do not embed',
1015 'content.',
1016 ),
Matt Menke59716d02018-04-05 12:45:531017 False,
Matt Menke7f520a82018-03-28 21:38:371018 (
Egor Paskoce145c42018-09-28 19:31:041019 r'^ios[\\/].*\.(cc|h)$',
1020 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:371021 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:041022 r'^net[\\/].*\.(cc|h)$',
1023 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Fabrice de Gans-Riberi9345311c2019-08-30 23:33:431024 r'^fuchsia/base/test_devtools_list_fetcher\.cc$',
Matt Menke7f520a82018-03-28 21:38:371025 ),
1026 ),
jdoerried7d10ab2018-04-27 10:46:131027 (
Dave Tapuska98199b612019-07-10 13:30:441028 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471029 (
1030 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1031 'base::RandomShuffle instead.'
1032 ),
1033 True,
1034 (),
1035 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241036 (
1037 'ios/web/public/test/http_server',
1038 (
1039 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1040 ),
1041 False,
1042 (),
1043 ),
Robert Liao764c9492019-01-24 18:46:281044 (
1045 'GetAddressOf',
1046 (
1047 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Robert Liaoe794041e2019-10-03 17:16:461048 'implicated in a few leaks. Use operator& instead. See ',
1049 'http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:281050 ),
1051 True,
1052 (),
1053 ),
Antonio Gomes07300d02019-03-13 20:59:571054 (
1055 'DEFINE_TYPE_CASTS',
1056 (
1057 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
1058 '//third_party/blink/renderer/platform/casting.h.'
1059 ),
1060 True,
1061 (
1062 r'^third_party/blink/renderer/.*\.(cc|h)$',
1063 ),
1064 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381065 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371066 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381067 (
1068 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1069 ),
1070 True,
1071 (),
1072 ),
Ben Lewisa9514602019-04-29 17:53:051073 (
1074 'SHFileOperation',
1075 (
1076 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1077 'complex functions to achieve the same goals. Use IFileOperation for ',
1078 'any esoteric actions instead.'
1079 ),
1080 True,
1081 (),
1082 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181083 (
Cliff Smolinsky81951642019-04-30 21:39:511084 'StringFromGUID2',
1085 (
1086 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1087 'Use base::win::String16FromGUID instead.'
1088 ),
1089 True,
1090 (
1091 r'/base/win/win_util_unittest.cc'
1092 ),
1093 ),
1094 (
1095 'StringFromCLSID',
1096 (
1097 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1098 'Use base::win::String16FromGUID instead.'
1099 ),
1100 True,
1101 (
1102 r'/base/win/win_util_unittest.cc'
1103 ),
1104 ),
1105 (
Avi Drissman7382afa02019-04-29 23:27:131106 'kCFAllocatorNull',
1107 (
1108 'The use of kCFAllocatorNull with the NoCopy creation of ',
1109 'CoreFoundation types is prohibited.',
1110 ),
1111 True,
1112 (),
1113 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291114 (
1115 'mojo::ConvertTo',
1116 (
1117 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1118 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1119 'StringTraits if you would like to convert between custom types and',
1120 'the wire format of mojom types.'
1121 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221122 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291123 (
Wezf89dec092019-09-11 19:38:331124 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1125 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291126 r'^third_party/blink/.*\.(cc|h)$',
1127 r'^content/renderer/.*\.(cc|h)$',
1128 ),
1129 ),
[email protected]127f18ec2012-06-16 05:05:591130)
1131
Mario Sanchez Prada2472cab2019-09-18 10:58:311132# Format: Sequence of tuples containing:
1133# * String pattern or, if starting with a slash, a regular expression.
1134# * Sequence of strings to show when the pattern matches.
1135_DEPRECATED_MOJO_TYPES = (
1136 (
1137 r'/\bmojo::AssociatedBinding\b',
1138 (
1139 'mojo::AssociatedBinding<Interface> is deprecated.',
1140 'Use mojo::AssociatedReceiver<Interface> instead.',
1141 ),
1142 ),
1143 (
1144 r'/\bmojo::AssociatedBindingSet\b',
1145 (
1146 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1147 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1148 ),
1149 ),
1150 (
1151 r'/\bmojo::AssociatedInterfacePtr\b',
1152 (
1153 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1154 'Use mojo::AssociatedRemote<Interface> instead.',
1155 ),
1156 ),
1157 (
1158 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1159 (
1160 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1161 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1162 ),
1163 ),
1164 (
1165 r'/\bmojo::AssociatedInterfaceRequest\b',
1166 (
1167 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1168 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1169 ),
1170 ),
1171 (
1172 r'/\bmojo::Binding\b',
1173 (
1174 'mojo::Binding<Interface> is deprecated.',
1175 'Use mojo::Receiver<Interface> instead.',
1176 ),
1177 ),
1178 (
1179 r'/\bmojo::BindingSet\b',
1180 (
1181 'mojo::BindingSet<Interface> is deprecated.',
1182 'Use mojo::ReceiverSet<Interface> instead.',
1183 ),
1184 ),
1185 (
1186 r'/\bmojo::InterfacePtr\b',
1187 (
1188 'mojo::InterfacePtr<Interface> is deprecated.',
1189 'Use mojo::Remote<Interface> instead.',
1190 ),
1191 ),
1192 (
1193 r'/\bmojo::InterfacePtrInfo\b',
1194 (
1195 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1196 'Use mojo::PendingRemote<Interface> instead.',
1197 ),
1198 ),
1199 (
1200 r'/\bmojo::InterfaceRequest\b',
1201 (
1202 'mojo::InterfaceRequest<Interface> is deprecated.',
1203 'Use mojo::PendingReceiver<Interface> instead.',
1204 ),
1205 ),
1206 (
1207 r'/\bmojo::MakeRequest\b',
1208 (
1209 'mojo::MakeRequest is deprecated.',
1210 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1211 ),
1212 ),
1213 (
1214 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1215 (
1216 'mojo::MakeRequest is deprecated.',
1217 'Use mojo::AssociatedRemote::'
1218 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1219 ),
1220 ),
1221 (
1222 r'/\bmojo::MakeStrongBinding\b',
1223 (
1224 'mojo::MakeStrongBinding is deprecated.',
1225 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1226 'mojo::MakeSelfOwnedReceiver() instead.',
1227 ),
1228 ),
1229 (
1230 r'/\bmojo::MakeStrongAssociatedBinding\b',
1231 (
1232 'mojo::MakeStrongAssociatedBinding is deprecated.',
1233 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1234 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1235 ),
1236 ),
1237 (
1238 r'/\bmojo::StrongAssociatedBindingSet\b',
1239 (
1240 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1241 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1242 ),
1243 ),
1244 (
1245 r'/\bmojo::StrongBindingSet\b',
1246 (
1247 'mojo::StrongBindingSet<Interface> is deprecated.',
1248 'Use mojo::UniqueReceiverSet<Interface> instead.',
1249 ),
1250 ),
1251)
wnwenbdc444e2016-05-25 13:44:151252
mlamouria82272622014-09-16 18:45:041253_IPC_ENUM_TRAITS_DEPRECATED = (
1254 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501255 'See http://www.chromium.org/Home/chromium-security/education/'
1256 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041257
Stephen Martinis97a394142018-06-07 23:06:051258_LONG_PATH_ERROR = (
1259 'Some files included in this CL have file names that are too long (> 200'
1260 ' characters). If committed, these files will cause issues on Windows. See'
1261 ' https://crbug.com/612667 for more details.'
1262)
1263
Shenghua Zhangbfaa38b82017-11-16 21:58:021264_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041265 r".*[\\/]BuildHooksAndroidImpl\.java",
1266 r".*[\\/]LicenseContentProvider\.java",
1267 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281268 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021269]
[email protected]127f18ec2012-06-16 05:05:591270
Sean Kau46e29bc2017-08-28 16:31:161271# These paths contain test data and other known invalid JSON files.
1272_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041273 r'test[\\/]data[\\/]',
1274 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1275 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041276 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431277 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161278]
1279
1280
[email protected]b00342e7f2013-03-26 16:21:541281_VALID_OS_MACROS = (
1282 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081283 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121285 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541286 'OS_BSD',
1287 'OS_CAT', # For testing.
1288 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041289 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541290 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371291 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541292 'OS_IOS',
1293 'OS_LINUX',
1294 'OS_MACOSX',
1295 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211296 'OS_NACL_NONSFI',
1297 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121298 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541299 'OS_OPENBSD',
1300 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371301 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541302 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541303 'OS_WIN',
1304)
1305
1306
agrievef32bcc72016-04-04 14:57:401307_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391308 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'base/android/jni_generator/jni_generator.pydeps',
1310 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221311 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361312 'build/android/gyp/aar.pydeps',
1313 'build/android/gyp/aidl.pydeps',
1314 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381315 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'build/android/gyp/bytecode_processor.pydeps',
1317 'build/android/gyp/compile_resources.pydeps',
Tibor Goldschwendt84ec04c2019-08-23 21:19:091318 'build/android/gyp/create_app_bundle_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1320 'build/android/gyp/copy_ex.pydeps',
1321 'build/android/gyp/create_app_bundle.pydeps',
1322 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221324 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591326 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/dex.pydeps',
1328 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/filter_zip.pydeps',
1330 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361331 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581333 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261335 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/javac.pydeps',
1337 'build/android/gyp/jinja_template.pydeps',
1338 'build/android/gyp/lint.pydeps',
1339 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/merge_manifest.pydeps',
1341 'build/android/gyp/prepare_resources.pydeps',
1342 'build/android/gyp/proguard.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241343 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461345 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561346 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361347 'build/android/incremental_install/generate_android_manifest.pydeps',
1348 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221349 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401350 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041351 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411353 'chrome/android/features/create_stripped_java_factory.pydeps',
Tibor Goldschwendtc748dfca42019-10-24 19:39:051354 'components/module_installer/android/module_desc_java.pydeps',
agrieve732db3a2016-04-26 19:18:191355 'net/tools/testserver/testserver.pydeps',
Andrew Luo338fe6e82019-09-19 07:17:431356 'testing/scripts/run_android_wpt.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021357 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:401358]
1359
wnwenbdc444e2016-05-25 13:44:151360
agrievef32bcc72016-04-04 14:57:401361_GENERIC_PYDEPS_FILES = [
anthonyvd7323c982019-09-11 14:36:421362 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131363 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421364 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1365 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131366 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061367 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221368 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401369]
1370
wnwenbdc444e2016-05-25 13:44:151371
agrievef32bcc72016-04-04 14:57:401372_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1373
1374
Eric Boren6fd2b932018-01-25 15:05:081375# Bypass the AUTHORS check for these accounts.
1376_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:291377 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
1378 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:081379 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:321380 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:591381 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451382 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591383 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:221384 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041385 ) | set('%[email protected]' % s
1386 for s in ('chromium-autoroll',)
1387 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301388 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081389
1390
Daniel Bratell65b033262019-04-23 08:17:061391def _IsCPlusPlusFile(input_api, file_path):
1392 """Returns True if this file contains C++-like code (and not Python,
1393 Go, Java, MarkDown, ...)"""
1394
1395 ext = input_api.os_path.splitext(file_path)[1]
1396 # This list is compatible with CppChecker.IsCppFile but we should
1397 # consider adding ".c" to it. If we do that we can use this function
1398 # at more places in the code.
1399 return ext in (
1400 '.h',
1401 '.cc',
1402 '.cpp',
1403 '.m',
1404 '.mm',
1405 )
1406
1407def _IsCPlusPlusHeaderFile(input_api, file_path):
1408 return input_api.os_path.splitext(file_path)[1] == ".h"
1409
1410
1411def _IsJavaFile(input_api, file_path):
1412 return input_api.os_path.splitext(file_path)[1] == ".java"
1413
1414
1415def _IsProtoFile(input_api, file_path):
1416 return input_api.os_path.splitext(file_path)[1] == ".proto"
1417
[email protected]55459852011-08-10 15:17:191418def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1419 """Attempts to prevent use of functions intended only for testing in
1420 non-testing code. For now this is just a best-effort implementation
1421 that ignores header files and may have some false positives. A
1422 better implementation would probably need a proper C++ parser.
1423 """
1424 # We only scan .cc files and the like, as the declaration of
1425 # for-testing functions in header files are hard to distinguish from
1426 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491427 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191428
jochenc0d4808c2015-07-27 09:25:421429 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191430 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091431 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191432 exclusion_pattern = input_api.re.compile(
1433 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1434 base_function_pattern, base_function_pattern))
1435
1436 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441437 black_list = (_EXCLUDED_PATHS +
1438 _TEST_CODE_EXCLUDED_PATHS +
1439 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191440 return input_api.FilterSourceFile(
1441 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491442 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191443 black_list=black_list)
1444
1445 problems = []
1446 for f in input_api.AffectedSourceFiles(FilterFile):
1447 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241448 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031449 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461450 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031451 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191452 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031453 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191454
1455 if problems:
[email protected]f7051d52013-04-02 18:31:421456 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031457 else:
1458 return []
[email protected]55459852011-08-10 15:17:191459
1460
Vaclav Brozek7dbc28c2018-03-27 08:35:231461def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1462 """This is a simplified version of
1463 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1464 """
1465 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1466 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1467 name_pattern = r'ForTest(s|ing)?'
1468 # Describes an occurrence of "ForTest*" inside a // comment.
1469 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1470 # Catch calls.
1471 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1472 # Ignore definitions. (Comments are ignored separately.)
1473 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1474
1475 problems = []
1476 sources = lambda x: input_api.FilterSourceFile(
1477 x,
1478 black_list=(('(?i).*test', r'.*\/junit\/')
1479 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491480 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231481 )
1482 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1483 local_path = f.LocalPath()
1484 is_inside_javadoc = False
1485 for line_number, line in f.ChangedContents():
1486 if is_inside_javadoc and javadoc_end_re.search(line):
1487 is_inside_javadoc = False
1488 if not is_inside_javadoc and javadoc_start_re.search(line):
1489 is_inside_javadoc = True
1490 if is_inside_javadoc:
1491 continue
1492 if (inclusion_re.search(line) and
1493 not comment_re.search(line) and
1494 not exclusion_re.search(line)):
1495 problems.append(
1496 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1497
1498 if problems:
1499 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1500 else:
1501 return []
1502
1503
[email protected]10689ca2011-09-02 02:31:541504def _CheckNoIOStreamInHeaders(input_api, output_api):
1505 """Checks to make sure no .h files include <iostream>."""
1506 files = []
1507 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1508 input_api.re.MULTILINE)
1509 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1510 if not f.LocalPath().endswith('.h'):
1511 continue
1512 contents = input_api.ReadFile(f)
1513 if pattern.search(contents):
1514 files.append(f)
1515
1516 if len(files):
yolandyandaabc6d2016-04-18 18:29:391517 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061518 'Do not #include <iostream> in header files, since it inserts static '
1519 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541520 '#include <ostream>. See http://crbug.com/94794',
1521 files) ]
1522 return []
1523
Danil Chapovalov3518f362018-08-11 16:13:431524def _CheckNoStrCatRedefines(input_api, output_api):
1525 """Checks no windows headers with StrCat redefined are included directly."""
1526 files = []
1527 pattern_deny = input_api.re.compile(
1528 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1529 input_api.re.MULTILINE)
1530 pattern_allow = input_api.re.compile(
1531 r'^#include\s"base/win/windows_defines.inc"',
1532 input_api.re.MULTILINE)
1533 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1534 contents = input_api.ReadFile(f)
1535 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1536 files.append(f.LocalPath())
1537
1538 if len(files):
1539 return [output_api.PresubmitError(
1540 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1541 'directly since they pollute code with StrCat macro. Instead, '
1542 'include matching header from base/win. See http://crbug.com/856536',
1543 files) ]
1544 return []
1545
[email protected]10689ca2011-09-02 02:31:541546
[email protected]72df4e782012-06-21 16:28:181547def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521548 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181549 problems = []
1550 for f in input_api.AffectedFiles():
1551 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1552 continue
1553
1554 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041555 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181556 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1557
1558 if not problems:
1559 return []
1560 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1561 '\n'.join(problems))]
1562
Dominic Battre033531052018-09-24 15:45:341563def _CheckNoDISABLETypoInTests(input_api, output_api):
1564 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1565
1566 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1567 instead of DISABLED_. To filter false positives, reports are only generated
1568 if a corresponding MAYBE_ line exists.
1569 """
1570 problems = []
1571
1572 # The following two patterns are looked for in tandem - is a test labeled
1573 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1574 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1575 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1576
1577 # This is for the case that a test is disabled on all platforms.
1578 full_disable_pattern = input_api.re.compile(
1579 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1580 input_api.re.MULTILINE)
1581
Katie Df13948e2018-09-25 07:33:441582 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341583 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1584 continue
1585
1586 # Search for MABYE_, DISABLE_ pairs.
1587 disable_lines = {} # Maps of test name to line number.
1588 maybe_lines = {}
1589 for line_num, line in f.ChangedContents():
1590 disable_match = disable_pattern.search(line)
1591 if disable_match:
1592 disable_lines[disable_match.group(1)] = line_num
1593 maybe_match = maybe_pattern.search(line)
1594 if maybe_match:
1595 maybe_lines[maybe_match.group(1)] = line_num
1596
1597 # Search for DISABLE_ occurrences within a TEST() macro.
1598 disable_tests = set(disable_lines.keys())
1599 maybe_tests = set(maybe_lines.keys())
1600 for test in disable_tests.intersection(maybe_tests):
1601 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1602
1603 contents = input_api.ReadFile(f)
1604 full_disable_match = full_disable_pattern.search(contents)
1605 if full_disable_match:
1606 problems.append(' %s' % f.LocalPath())
1607
1608 if not problems:
1609 return []
1610 return [
1611 output_api.PresubmitPromptWarning(
1612 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1613 '\n'.join(problems))
1614 ]
1615
[email protected]72df4e782012-06-21 16:28:181616
danakj61c1aa22015-10-26 19:55:521617def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571618 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521619 errors = []
1620 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1621 input_api.re.MULTILINE)
1622 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1623 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1624 continue
1625 for lnum, line in f.ChangedContents():
1626 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171627 errors.append(output_api.PresubmitError(
1628 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571629 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171630 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521631 return errors
1632
1633
Makoto Shimazu3ad422cd2019-05-08 02:35:141634def _FindHistogramNameInChunk(histogram_name, chunk):
1635 """Tries to find a histogram name or prefix in a line.
1636
1637 Returns the existence of the histogram name, or None if it needs more chunk
1638 to determine."""
mcasasb7440c282015-02-04 14:52:191639 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1640 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141641 if '<affected-histogram' in chunk:
1642 # If the tag is not completed, needs more chunk to get the name.
1643 if not '>' in chunk:
1644 return None
1645 if not 'name="' in chunk:
1646 return False
1647 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1648 # expect the only attribute is the name.
1649 histogram_prefix = chunk.split('"')[1]
1650 return histogram_prefix in histogram_name
1651 # Typically the whole histogram name should in the line.
1652 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191653
1654
1655def _CheckUmaHistogramChanges(input_api, output_api):
1656 """Check that UMA histogram names in touched lines can still be found in other
1657 lines of the patch or in histograms.xml. Note that this check would not catch
1658 the reverse: changes in histograms.xml not matched in the code itself."""
1659 touched_histograms = []
1660 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471661 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1662 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1663 name_pattern = r'"(.*?)"'
1664 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1665 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1666 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1667 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1668 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171669 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191670 for f in input_api.AffectedFiles():
1671 # If histograms.xml itself is modified, keep the modified lines for later.
1672 if f.LocalPath().endswith(('histograms.xml')):
1673 histograms_xml_modifications = f.ChangedContents()
1674 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471675 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1676 single_line_re = single_line_c_re
1677 split_line_prefix_re = split_line_c_prefix_re
1678 elif f.LocalPath().endswith(('java')):
1679 single_line_re = single_line_java_re
1680 split_line_prefix_re = split_line_java_prefix_re
1681 else:
mcasasb7440c282015-02-04 14:52:191682 continue
1683 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171684 if last_line_matched_prefix:
1685 suffix_found = split_line_suffix_re.search(line)
1686 if suffix_found :
1687 touched_histograms.append([suffix_found.group(1), f, line_num])
1688 last_line_matched_prefix = False
1689 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061690 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191691 if found:
1692 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171693 continue
1694 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191695
1696 # Search for the touched histogram names in the local modifications to
1697 # histograms.xml, and, if not found, on the base histograms.xml file.
1698 unmatched_histograms = []
1699 for histogram_info in touched_histograms:
1700 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141701 chunk = ''
mcasasb7440c282015-02-04 14:52:191702 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141703 chunk += line
1704 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1705 if histogram_name_found is None:
1706 continue
1707 chunk = ''
mcasasb7440c282015-02-04 14:52:191708 if histogram_name_found:
1709 break
1710 if not histogram_name_found:
1711 unmatched_histograms.append(histogram_info)
1712
eromanb90c82e7e32015-04-01 15:13:491713 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191714 problems = []
1715 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491716 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191717 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451718 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191719 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141720 chunk = ''
mcasasb7440c282015-02-04 14:52:191721 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141722 chunk += line
1723 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1724 chunk)
1725 if histogram_name_found is None:
1726 continue
1727 chunk = ''
mcasasb7440c282015-02-04 14:52:191728 if histogram_name_found:
1729 break
1730 if not histogram_name_found:
1731 problems.append(' [%s:%d] %s' %
1732 (f.LocalPath(), line_num, histogram_name))
1733
1734 if not problems:
1735 return []
1736 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1737 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491738 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191739
wnwenbdc444e2016-05-25 13:44:151740
yolandyandaabc6d2016-04-18 18:29:391741def _CheckFlakyTestUsage(input_api, output_api):
1742 """Check that FlakyTest annotation is our own instead of the android one"""
1743 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1744 files = []
1745 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1746 if f.LocalPath().endswith('Test.java'):
1747 if pattern.search(input_api.ReadFile(f)):
1748 files.append(f)
1749 if len(files):
1750 return [output_api.PresubmitError(
1751 'Use org.chromium.base.test.util.FlakyTest instead of '
1752 'android.test.FlakyTest',
1753 files)]
1754 return []
mcasasb7440c282015-02-04 14:52:191755
wnwenbdc444e2016-05-25 13:44:151756
[email protected]8ea5d4b2011-09-13 21:49:221757def _CheckNoNewWStrings(input_api, output_api):
1758 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271759 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221760 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201761 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571762 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341763 '/win/' in f.LocalPath() or
1764 'chrome_elf' in f.LocalPath() or
1765 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201766 continue
[email protected]8ea5d4b2011-09-13 21:49:221767
[email protected]a11dbe9b2012-08-07 01:32:581768 allowWString = False
[email protected]b5c24292011-11-28 14:38:201769 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581770 if 'presubmit: allow wstring' in line:
1771 allowWString = True
1772 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271773 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581774 allowWString = False
1775 else:
1776 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221777
[email protected]55463aa62011-10-12 00:48:271778 if not problems:
1779 return []
1780 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581781 ' If you are calling a cross-platform API that accepts a wstring, '
1782 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271783 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221784
1785
[email protected]2a8ac9c2011-10-19 17:20:441786def _CheckNoDEPSGIT(input_api, output_api):
1787 """Make sure .DEPS.git is never modified manually."""
1788 if any(f.LocalPath().endswith('.DEPS.git') for f in
1789 input_api.AffectedFiles()):
1790 return [output_api.PresubmitError(
1791 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1792 'automated system based on what\'s in DEPS and your changes will be\n'
1793 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501794 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1795 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441796 'for more information')]
1797 return []
1798
1799
tandriief664692014-09-23 14:51:471800def _CheckValidHostsInDEPS(input_api, output_api):
1801 """Checks that DEPS file deps are from allowed_hosts."""
1802 # Run only if DEPS file has been modified to annoy fewer bystanders.
1803 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1804 return []
1805 # Outsource work to gclient verify
1806 try:
John Budorickf20c0042019-04-25 23:23:401807 gclient_path = input_api.os_path.join(
1808 input_api.PresubmitLocalPath(),
1809 'third_party', 'depot_tools', 'gclient.py')
1810 input_api.subprocess.check_output(
1811 [input_api.python_executable, gclient_path, 'verify'],
1812 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471813 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201814 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471815 return [output_api.PresubmitError(
1816 'DEPS file must have only git dependencies.',
1817 long_text=error.output)]
1818
1819
Mario Sanchez Prada2472cab2019-09-18 10:58:311820def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1821 type_name, message):
1822 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1823
1824 Returns an string composed of the name of the file, the line number where the
1825 match has been found and the additional text passed as |message| in case the
1826 target type name matches the text inside the line passed as parameter.
1827 """
1828 matched = False
1829 if type_name[0:1] == '/':
1830 regex = type_name[1:]
1831 if input_api.re.search(regex, line):
1832 matched = True
1833 elif type_name in line:
1834 matched = True
1835
1836 result = []
1837 if matched:
1838 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1839 for message_line in message:
1840 result.append(' %s' % message_line)
1841
1842 return result
1843
1844
[email protected]127f18ec2012-06-16 05:05:591845def _CheckNoBannedFunctions(input_api, output_api):
1846 """Make sure that banned functions are not used."""
1847 warnings = []
1848 errors = []
1849
wnwenbdc444e2016-05-25 13:44:151850 def IsBlacklisted(affected_file, blacklist):
1851 local_path = affected_file.LocalPath()
1852 for item in blacklist:
1853 if input_api.re.match(item, local_path):
1854 return True
1855 return False
1856
Peter K. Lee6c03ccff2019-07-15 14:40:051857 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541858 local_path = affected_file.LocalPath()
1859 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1860 return False
1861 basename = input_api.os_path.basename(local_path)
1862 if 'ios' in basename.split('_'):
1863 return True
1864 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1865 if sep and 'ios' in local_path.split(sep):
1866 return True
1867 return False
1868
wnwenbdc444e2016-05-25 13:44:151869 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311870 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1871 func_name, message)
1872 if problems:
wnwenbdc444e2016-05-25 13:44:151873 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311874 errors.extend(problems)
1875 else:
1876 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151877
Eric Stevensona9a980972017-09-23 00:04:411878 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1879 for f in input_api.AffectedFiles(file_filter=file_filter):
1880 for line_num, line in f.ChangedContents():
1881 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1882 CheckForMatch(f, line_num, line, func_name, message, error)
1883
[email protected]127f18ec2012-06-16 05:05:591884 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1885 for f in input_api.AffectedFiles(file_filter=file_filter):
1886 for line_num, line in f.ChangedContents():
1887 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151888 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591889
Peter K. Lee6c03ccff2019-07-15 14:40:051890 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541891 for line_num, line in f.ChangedContents():
1892 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1893 CheckForMatch(f, line_num, line, func_name, message, error)
1894
Peter K. Lee6c03ccff2019-07-15 14:40:051895 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1896 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1897 for line_num, line in f.ChangedContents():
1898 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1899 CheckForMatch(f, line_num, line, func_name, message, error)
1900
[email protected]127f18ec2012-06-16 05:05:591901 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1902 for f in input_api.AffectedFiles(file_filter=file_filter):
1903 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491904 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491905 if IsBlacklisted(f, excluded_paths):
1906 continue
wnwenbdc444e2016-05-25 13:44:151907 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591908
1909 result = []
1910 if (warnings):
1911 result.append(output_api.PresubmitPromptWarning(
1912 'Banned functions were used.\n' + '\n'.join(warnings)))
1913 if (errors):
1914 result.append(output_api.PresubmitError(
1915 'Banned functions were used.\n' + '\n'.join(errors)))
1916 return result
1917
1918
Mario Sanchez Prada2472cab2019-09-18 10:58:311919def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1920 """Make sure that old Mojo types are not used."""
1921 warnings = []
1922
1923 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1924 for f in input_api.AffectedFiles(file_filter=file_filter):
1925 # Only need to check Blink for warnings for now.
1926 if not f.LocalPath().startswith('third_party/blink'):
1927 continue
1928
1929 for line_num, line in f.ChangedContents():
1930 for func_name, message in _DEPRECATED_MOJO_TYPES:
1931 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1932 func_name, message)
1933 if problems:
1934 warnings.extend(problems)
1935
1936 result = []
1937 if (warnings):
1938 result.append(output_api.PresubmitPromptWarning(
1939 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
1940 return result
1941
1942
[email protected]6c063c62012-07-11 19:11:061943def _CheckNoPragmaOnce(input_api, output_api):
1944 """Make sure that banned functions are not used."""
1945 files = []
1946 pattern = input_api.re.compile(r'^#pragma\s+once',
1947 input_api.re.MULTILINE)
1948 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1949 if not f.LocalPath().endswith('.h'):
1950 continue
1951 contents = input_api.ReadFile(f)
1952 if pattern.search(contents):
1953 files.append(f)
1954
1955 if files:
1956 return [output_api.PresubmitError(
1957 'Do not use #pragma once in header files.\n'
1958 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1959 files)]
1960 return []
1961
[email protected]127f18ec2012-06-16 05:05:591962
[email protected]e7479052012-09-19 00:26:121963def _CheckNoTrinaryTrueFalse(input_api, output_api):
1964 """Checks to make sure we don't introduce use of foo ? true : false."""
1965 problems = []
1966 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1967 for f in input_api.AffectedFiles():
1968 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1969 continue
1970
1971 for line_num, line in f.ChangedContents():
1972 if pattern.match(line):
1973 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1974
1975 if not problems:
1976 return []
1977 return [output_api.PresubmitPromptWarning(
1978 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1979 '\n'.join(problems))]
1980
1981
[email protected]55f9f382012-07-31 11:02:181982def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281983 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181984 change. Breaking - rules is an error, breaking ! rules is a
1985 warning.
1986 """
mohan.reddyf21db962014-10-16 12:26:471987 import sys
[email protected]55f9f382012-07-31 11:02:181988 # We need to wait until we have an input_api object and use this
1989 # roundabout construct to import checkdeps because this file is
1990 # eval-ed and thus doesn't have __file__.
1991 original_sys_path = sys.path
1992 try:
1993 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471994 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181995 import checkdeps
[email protected]55f9f382012-07-31 11:02:181996 from rules import Rule
1997 finally:
1998 # Restore sys.path to what it was before.
1999 sys.path = original_sys_path
2000
2001 added_includes = []
rhalavati08acd232017-04-03 07:23:282002 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242003 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182004 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062005 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502006 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082007 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062008 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502009 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082010 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062011 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502012 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082013 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182014
[email protected]26385172013-05-09 23:11:352015 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182016
2017 error_descriptions = []
2018 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282019 error_subjects = set()
2020 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182021 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2022 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082023 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182024 description_with_path = '%s\n %s' % (path, rule_description)
2025 if rule_type == Rule.DISALLOW:
2026 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282027 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182028 else:
2029 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282030 warning_subjects.add("#includes")
2031
2032 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2033 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082034 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282035 description_with_path = '%s\n %s' % (path, rule_description)
2036 if rule_type == Rule.DISALLOW:
2037 error_descriptions.append(description_with_path)
2038 error_subjects.add("imports")
2039 else:
2040 warning_descriptions.append(description_with_path)
2041 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182042
Jinsuk Kim5a092672017-10-24 22:42:242043 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022044 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082045 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242046 description_with_path = '%s\n %s' % (path, rule_description)
2047 if rule_type == Rule.DISALLOW:
2048 error_descriptions.append(description_with_path)
2049 error_subjects.add("imports")
2050 else:
2051 warning_descriptions.append(description_with_path)
2052 warning_subjects.add("imports")
2053
[email protected]55f9f382012-07-31 11:02:182054 results = []
2055 if error_descriptions:
2056 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282057 'You added one or more %s that violate checkdeps rules.'
2058 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182059 error_descriptions))
2060 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422061 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282062 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182063 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282064 '%s? See relevant DEPS file(s) for details and contacts.' %
2065 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182066 warning_descriptions))
2067 return results
2068
2069
[email protected]fbcafe5a2012-08-08 15:31:222070def _CheckFilePermissions(input_api, output_api):
2071 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152072 if input_api.platform == 'win32':
2073 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292074 checkperms_tool = input_api.os_path.join(
2075 input_api.PresubmitLocalPath(),
2076 'tools', 'checkperms', 'checkperms.py')
2077 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472078 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392079 with input_api.CreateTemporaryFile() as file_list:
2080 for f in input_api.AffectedFiles():
2081 # checkperms.py file/directory arguments must be relative to the
2082 # repository.
2083 file_list.write(f.LocalPath() + '\n')
2084 file_list.close()
2085 args += ['--file-list', file_list.name]
2086 try:
2087 input_api.subprocess.check_output(args)
2088 return []
2089 except input_api.subprocess.CalledProcessError as error:
2090 return [output_api.PresubmitError(
2091 'checkperms.py failed:',
2092 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222093
2094
robertocn832f5992017-01-04 19:01:302095def _CheckTeamTags(input_api, output_api):
2096 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2097 checkteamtags_tool = input_api.os_path.join(
2098 input_api.PresubmitLocalPath(),
2099 'tools', 'checkteamtags', 'checkteamtags.py')
2100 args = [input_api.python_executable, checkteamtags_tool,
2101 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222102 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302103 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2104 'OWNERS']
2105 try:
2106 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052107 warnings = input_api.subprocess.check_output(args + files).splitlines()
2108 if warnings:
2109 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302110 return []
2111 except input_api.subprocess.CalledProcessError as error:
2112 return [output_api.PresubmitError(
2113 'checkteamtags.py failed:',
2114 long_text=error.output)]
2115
2116
[email protected]c8278b32012-10-30 20:35:492117def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2118 """Makes sure we don't include ui/aura/window_property.h
2119 in header files.
2120 """
2121 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2122 errors = []
2123 for f in input_api.AffectedFiles():
2124 if not f.LocalPath().endswith('.h'):
2125 continue
2126 for line_num, line in f.ChangedContents():
2127 if pattern.match(line):
2128 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2129
2130 results = []
2131 if errors:
2132 results.append(output_api.PresubmitError(
2133 'Header files should not include ui/aura/window_property.h', errors))
2134 return results
2135
2136
[email protected]70ca77752012-11-20 03:45:032137def _CheckForVersionControlConflictsInFile(input_api, f):
2138 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2139 errors = []
2140 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162141 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232142 # First-level headers in markdown look a lot like version control
2143 # conflict markers. http://daringfireball.net/projects/markdown/basics
2144 continue
[email protected]70ca77752012-11-20 03:45:032145 if pattern.match(line):
2146 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2147 return errors
2148
2149
2150def _CheckForVersionControlConflicts(input_api, output_api):
2151 """Usually this is not intentional and will cause a compile failure."""
2152 errors = []
2153 for f in input_api.AffectedFiles():
2154 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2155
2156 results = []
2157 if errors:
2158 results.append(output_api.PresubmitError(
2159 'Version control conflict markers found, please resolve.', errors))
2160 return results
2161
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202162
estadee17314a02017-01-12 16:22:162163def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2164 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2165 errors = []
2166 for f in input_api.AffectedFiles():
2167 for line_num, line in f.ChangedContents():
2168 if pattern.search(line):
2169 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2170
2171 results = []
2172 if errors:
2173 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502174 'Found Google support URL addressed by answer number. Please replace '
2175 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162176 return results
2177
[email protected]70ca77752012-11-20 03:45:032178
[email protected]06e6d0ff2012-12-11 01:36:442179def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2180 def FilterFile(affected_file):
2181 """Filter function for use with input_api.AffectedSourceFiles,
2182 below. This filters out everything except non-test files from
2183 top-level directories that generally speaking should not hard-code
2184 service URLs (e.g. src/android_webview/, src/content/ and others).
2185 """
2186 return input_api.FilterSourceFile(
2187 affected_file,
Egor Paskoce145c42018-09-28 19:31:042188 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442189 black_list=(_EXCLUDED_PATHS +
2190 _TEST_CODE_EXCLUDED_PATHS +
2191 input_api.DEFAULT_BLACK_LIST))
2192
reillyi38965732015-11-16 18:27:332193 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2194 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462195 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2196 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442197 problems = [] # items are (filename, line_number, line)
2198 for f in input_api.AffectedSourceFiles(FilterFile):
2199 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462200 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442201 problems.append((f.LocalPath(), line_num, line))
2202
2203 if problems:
[email protected]f7051d52013-04-02 18:31:422204 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442205 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582206 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442207 [' %s:%d: %s' % (
2208 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032209 else:
2210 return []
[email protected]06e6d0ff2012-12-11 01:36:442211
2212
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492213# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272214def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2215 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312216 The native_client_sdk directory is excluded because it has auto-generated PNG
2217 files for documentation.
[email protected]d2530012013-01-25 16:39:272218 """
[email protected]d2530012013-01-25 16:39:272219 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492220 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042221 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312222 file_filter = lambda f: input_api.FilterSourceFile(
2223 f, white_list=white_list, black_list=black_list)
2224 for f in input_api.AffectedFiles(include_deletes=False,
2225 file_filter=file_filter):
2226 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272227
2228 results = []
2229 if errors:
2230 results.append(output_api.PresubmitError(
2231 'The name of PNG files should not have abbreviations. \n'
2232 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2233 'Contact [email protected] if you have questions.', errors))
2234 return results
2235
2236
Daniel Cheng4dcdb6b2017-04-13 08:30:172237def _ExtractAddRulesFromParsedDeps(parsed_deps):
2238 """Extract the rules that add dependencies from a parsed DEPS file.
2239
2240 Args:
2241 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2242 add_rules = set()
2243 add_rules.update([
2244 rule[1:] for rule in parsed_deps.get('include_rules', [])
2245 if rule.startswith('+') or rule.startswith('!')
2246 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502247 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172248 {}).iteritems():
2249 add_rules.update([
2250 rule[1:] for rule in rules
2251 if rule.startswith('+') or rule.startswith('!')
2252 ])
2253 return add_rules
2254
2255
2256def _ParseDeps(contents):
2257 """Simple helper for parsing DEPS files."""
2258 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172259 class _VarImpl:
2260
2261 def __init__(self, local_scope):
2262 self._local_scope = local_scope
2263
2264 def Lookup(self, var_name):
2265 """Implements the Var syntax."""
2266 try:
2267 return self._local_scope['vars'][var_name]
2268 except KeyError:
2269 raise Exception('Var is not defined: %s' % var_name)
2270
2271 local_scope = {}
2272 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172273 'Var': _VarImpl(local_scope).Lookup,
2274 }
2275 exec contents in global_scope, local_scope
2276 return local_scope
2277
2278
2279def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082280 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412281 a set of DEPS entries that we should look up.
2282
2283 For a directory (rather than a specific filename) we fake a path to
2284 a specific filename by adding /DEPS. This is chosen as a file that
2285 will seldom or never be subject to per-file include_rules.
2286 """
[email protected]2b438d62013-11-14 17:54:142287 # We ignore deps entries on auto-generated directories.
2288 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082289
Daniel Cheng4dcdb6b2017-04-13 08:30:172290 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2291 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2292
2293 added_deps = new_deps.difference(old_deps)
2294
[email protected]2b438d62013-11-14 17:54:142295 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172296 for added_dep in added_deps:
2297 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2298 continue
2299 # Assume that a rule that ends in .h is a rule for a specific file.
2300 if added_dep.endswith('.h'):
2301 results.add(added_dep)
2302 else:
2303 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082304 return results
2305
2306
[email protected]e871964c2013-05-13 14:14:552307def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2308 """When a dependency prefixed with + is added to a DEPS file, we
2309 want to make sure that the change is reviewed by an OWNER of the
2310 target file or directory, to avoid layering violations from being
2311 introduced. This check verifies that this happens.
2312 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172313 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242314
2315 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492316 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242317 for f in input_api.AffectedFiles(include_deletes=False,
2318 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552319 filename = input_api.os_path.basename(f.LocalPath())
2320 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172321 virtual_depended_on_files.update(_CalculateAddedDeps(
2322 input_api.os_path,
2323 '\n'.join(f.OldContents()),
2324 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552325
[email protected]e871964c2013-05-13 14:14:552326 if not virtual_depended_on_files:
2327 return []
2328
2329 if input_api.is_committing:
2330 if input_api.tbr:
2331 return [output_api.PresubmitNotifyResult(
2332 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272333 if input_api.dry_run:
2334 return [output_api.PresubmitNotifyResult(
2335 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552336 if not input_api.change.issue:
2337 return [output_api.PresubmitError(
2338 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402339 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552340 output = output_api.PresubmitError
2341 else:
2342 output = output_api.PresubmitNotifyResult
2343
2344 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502345 owner_email, reviewers = (
2346 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2347 input_api,
2348 owners_db.email_regexp,
2349 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552350
2351 owner_email = owner_email or input_api.change.author_email
2352
[email protected]de4f7d22013-05-23 14:27:462353 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512354 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462355 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552356 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2357 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412358
2359 # We strip the /DEPS part that was added by
2360 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2361 # directory.
2362 def StripDeps(path):
2363 start_deps = path.rfind('/DEPS')
2364 if start_deps != -1:
2365 return path[:start_deps]
2366 else:
2367 return path
2368 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552369 for path in missing_files]
2370
2371 if unapproved_dependencies:
2372 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152373 output('You need LGTM from owners of depends-on paths in DEPS that were '
2374 'modified in this CL:\n %s' %
2375 '\n '.join(sorted(unapproved_dependencies)))]
2376 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2377 output_list.append(output(
2378 'Suggested missing target path OWNERS:\n %s' %
2379 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552380 return output_list
2381
2382 return []
2383
2384
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492385# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402386def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492387 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402388 black_list = (_EXCLUDED_PATHS +
2389 _TEST_CODE_EXCLUDED_PATHS +
2390 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042391 (r"^base[\\/]logging\.h$",
2392 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222393 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042394 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2395 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2396 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122397 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182398 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152399 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032400 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152401 r"^chrome[\\/]chrome_cleaner[\\/].*",
2402 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2403 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042404 r"^chromecast[\\/]",
2405 r"^cloud_print[\\/]",
2406 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482407 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:042408 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:312409 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042410 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462411 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042412 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462413 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042414 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252415 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042416 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2417 r"^courgette[\\/]courgette_tool\.cc$",
2418 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272419 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332420 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042421 r"^ipc[\\/]ipc_logging\.cc$",
2422 r"^native_client_sdk[\\/]",
2423 r"^remoting[\\/]base[\\/]logging\.h$",
2424 r"^remoting[\\/]host[\\/].*",
2425 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062426 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332427 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042428 r"^tools[\\/]",
2429 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2430 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332431 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402432 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492433 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402434
thomasanderson625d3932017-03-29 07:16:582435 log_info = set([])
2436 printf = set([])
[email protected]85218562013-11-22 07:41:402437
2438 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582439 for _, line in f.ChangedContents():
2440 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2441 log_info.add(f.LocalPath())
2442 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2443 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372444
thomasanderson625d3932017-03-29 07:16:582445 if input_api.re.search(r"\bprintf\(", line):
2446 printf.add(f.LocalPath())
2447 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2448 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402449
2450 if log_info:
2451 return [output_api.PresubmitError(
2452 'These files spam the console log with LOG(INFO):',
2453 items=log_info)]
2454 if printf:
2455 return [output_api.PresubmitError(
2456 'These files spam the console log with printf/fprintf:',
2457 items=printf)]
2458 return []
2459
2460
[email protected]49aa76a2013-12-04 06:59:162461def _CheckForAnonymousVariables(input_api, output_api):
2462 """These types are all expected to hold locks while in scope and
2463 so should never be anonymous (which causes them to be immediately
2464 destroyed)."""
2465 they_who_must_be_named = [
2466 'base::AutoLock',
2467 'base::AutoReset',
2468 'base::AutoUnlock',
2469 'SkAutoAlphaRestore',
2470 'SkAutoBitmapShaderInstall',
2471 'SkAutoBlitterChoose',
2472 'SkAutoBounderCommit',
2473 'SkAutoCallProc',
2474 'SkAutoCanvasRestore',
2475 'SkAutoCommentBlock',
2476 'SkAutoDescriptor',
2477 'SkAutoDisableDirectionCheck',
2478 'SkAutoDisableOvalCheck',
2479 'SkAutoFree',
2480 'SkAutoGlyphCache',
2481 'SkAutoHDC',
2482 'SkAutoLockColors',
2483 'SkAutoLockPixels',
2484 'SkAutoMalloc',
2485 'SkAutoMaskFreeImage',
2486 'SkAutoMutexAcquire',
2487 'SkAutoPathBoundsUpdate',
2488 'SkAutoPDFRelease',
2489 'SkAutoRasterClipValidate',
2490 'SkAutoRef',
2491 'SkAutoTime',
2492 'SkAutoTrace',
2493 'SkAutoUnref',
2494 ]
2495 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2496 # bad: base::AutoLock(lock.get());
2497 # not bad: base::AutoLock lock(lock.get());
2498 bad_pattern = input_api.re.compile(anonymous)
2499 # good: new base::AutoLock(lock.get())
2500 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2501 errors = []
2502
2503 for f in input_api.AffectedFiles():
2504 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2505 continue
2506 for linenum, line in f.ChangedContents():
2507 if bad_pattern.search(line) and not good_pattern.search(line):
2508 errors.append('%s:%d' % (f.LocalPath(), linenum))
2509
2510 if errors:
2511 return [output_api.PresubmitError(
2512 'These lines create anonymous variables that need to be named:',
2513 items=errors)]
2514 return []
2515
2516
Peter Kasting4844e46e2018-02-23 07:27:102517def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532518 # Returns whether |template_str| is of the form <T, U...> for some types T
2519 # and U. Assumes that |template_str| is already in the form <...>.
2520 def HasMoreThanOneArg(template_str):
2521 # Level of <...> nesting.
2522 nesting = 0
2523 for c in template_str:
2524 if c == '<':
2525 nesting += 1
2526 elif c == '>':
2527 nesting -= 1
2528 elif c == ',' and nesting == 1:
2529 return True
2530 return False
2531
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492532 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102533 sources = lambda affected_file: input_api.FilterSourceFile(
2534 affected_file,
2535 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2536 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492537 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552538
2539 # Pattern to capture a single "<...>" block of template arguments. It can
2540 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2541 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2542 # latter would likely require counting that < and > match, which is not
2543 # expressible in regular languages. Should the need arise, one can introduce
2544 # limited counting (matching up to a total number of nesting depth), which
2545 # should cover all practical cases for already a low nesting limit.
2546 template_arg_pattern = (
2547 r'<[^>]*' # Opening block of <.
2548 r'>([^<]*>)?') # Closing block of >.
2549 # Prefix expressing that whatever follows is not already inside a <...>
2550 # block.
2551 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102552 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552553 not_inside_template_arg_pattern
2554 + r'\bstd::unique_ptr'
2555 + template_arg_pattern
2556 + r'\(\)')
2557
2558 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2559 template_arg_no_array_pattern = (
2560 r'<[^>]*[^]]' # Opening block of <.
2561 r'>([^(<]*[^]]>)?') # Closing block of >.
2562 # Prefix saying that what follows is the start of an expression.
2563 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2564 # Suffix saying that what follows are call parentheses with a non-empty list
2565 # of arguments.
2566 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532567 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552568 return_construct_pattern = input_api.re.compile(
2569 start_of_expr_pattern
2570 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532571 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552572 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532573 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552574 + nonempty_arg_list_pattern)
2575
Vaclav Brozek851d9602018-04-04 16:13:052576 problems_constructor = []
2577 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102578 for f in input_api.AffectedSourceFiles(sources):
2579 for line_number, line in f.ChangedContents():
2580 # Disallow:
2581 # return std::unique_ptr<T>(foo);
2582 # bar = std::unique_ptr<T>(foo);
2583 # But allow:
2584 # return std::unique_ptr<T[]>(foo);
2585 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532586 # And also allow cases when the second template argument is present. Those
2587 # cases cannot be handled by std::make_unique:
2588 # return std::unique_ptr<T, U>(foo);
2589 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052590 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532591 return_construct_result = return_construct_pattern.search(line)
2592 if return_construct_result and not HasMoreThanOneArg(
2593 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052594 problems_constructor.append(
2595 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102596 # Disallow:
2597 # std::unique_ptr<T>()
2598 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052599 problems_nullptr.append(
2600 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2601
2602 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162603 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052604 errors.append(output_api.PresubmitError(
2605 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162606 problems_nullptr))
2607 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052608 errors.append(output_api.PresubmitError(
2609 'The following files use explicit std::unique_ptr constructor.'
2610 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162611 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102612 return errors
2613
2614
[email protected]999261d2014-03-03 20:08:082615def _CheckUserActionUpdate(input_api, output_api):
2616 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522617 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082618 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522619 # If actions.xml is already included in the changelist, the PRESUBMIT
2620 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082621 return []
2622
[email protected]999261d2014-03-03 20:08:082623 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2624 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522625 current_actions = None
[email protected]999261d2014-03-03 20:08:082626 for f in input_api.AffectedFiles(file_filter=file_filter):
2627 for line_num, line in f.ChangedContents():
2628 match = input_api.re.search(action_re, line)
2629 if match:
[email protected]2f92dec2014-03-07 19:21:522630 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2631 # loaded only once.
2632 if not current_actions:
2633 with open('tools/metrics/actions/actions.xml') as actions_f:
2634 current_actions = actions_f.read()
2635 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082636 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522637 action = 'name="{0}"'.format(action_name)
2638 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082639 return [output_api.PresubmitPromptWarning(
2640 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522641 'tools/metrics/actions/actions.xml. Please run '
2642 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082643 % (f.LocalPath(), line_num, action_name))]
2644 return []
2645
2646
Daniel Cheng13ca61a882017-08-25 15:11:252647def _ImportJSONCommentEater(input_api):
2648 import sys
2649 sys.path = sys.path + [input_api.os_path.join(
2650 input_api.PresubmitLocalPath(),
2651 'tools', 'json_comment_eater')]
2652 import json_comment_eater
2653 return json_comment_eater
2654
2655
[email protected]99171a92014-06-03 08:44:472656def _GetJSONParseError(input_api, filename, eat_comments=True):
2657 try:
2658 contents = input_api.ReadFile(filename)
2659 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252660 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132661 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472662
2663 input_api.json.loads(contents)
2664 except ValueError as e:
2665 return e
2666 return None
2667
2668
2669def _GetIDLParseError(input_api, filename):
2670 try:
2671 contents = input_api.ReadFile(filename)
2672 idl_schema = input_api.os_path.join(
2673 input_api.PresubmitLocalPath(),
2674 'tools', 'json_schema_compiler', 'idl_schema.py')
2675 process = input_api.subprocess.Popen(
2676 [input_api.python_executable, idl_schema],
2677 stdin=input_api.subprocess.PIPE,
2678 stdout=input_api.subprocess.PIPE,
2679 stderr=input_api.subprocess.PIPE,
2680 universal_newlines=True)
2681 (_, error) = process.communicate(input=contents)
2682 return error or None
2683 except ValueError as e:
2684 return e
2685
2686
2687def _CheckParseErrors(input_api, output_api):
2688 """Check that IDL and JSON files do not contain syntax errors."""
2689 actions = {
2690 '.idl': _GetIDLParseError,
2691 '.json': _GetJSONParseError,
2692 }
[email protected]99171a92014-06-03 08:44:472693 # Most JSON files are preprocessed and support comments, but these do not.
2694 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042695 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472696 ]
2697 # Only run IDL checker on files in these directories.
2698 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042699 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2700 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472701 ]
2702
2703 def get_action(affected_file):
2704 filename = affected_file.LocalPath()
2705 return actions.get(input_api.os_path.splitext(filename)[1])
2706
[email protected]99171a92014-06-03 08:44:472707 def FilterFile(affected_file):
2708 action = get_action(affected_file)
2709 if not action:
2710 return False
2711 path = affected_file.LocalPath()
2712
Sean Kau46e29bc2017-08-28 16:31:162713 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472714 return False
2715
2716 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162717 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472718 return False
2719 return True
2720
2721 results = []
2722 for affected_file in input_api.AffectedFiles(
2723 file_filter=FilterFile, include_deletes=False):
2724 action = get_action(affected_file)
2725 kwargs = {}
2726 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162727 _MatchesFile(input_api, json_no_comments_patterns,
2728 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472729 kwargs['eat_comments'] = False
2730 parse_error = action(input_api,
2731 affected_file.AbsoluteLocalPath(),
2732 **kwargs)
2733 if parse_error:
2734 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2735 (affected_file.LocalPath(), parse_error)))
2736 return results
2737
2738
[email protected]760deea2013-12-10 19:33:492739def _CheckJavaStyle(input_api, output_api):
2740 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472741 import sys
[email protected]760deea2013-12-10 19:33:492742 original_sys_path = sys.path
2743 try:
2744 sys.path = sys.path + [input_api.os_path.join(
2745 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2746 import checkstyle
2747 finally:
2748 # Restore sys.path to what it was before.
2749 sys.path = original_sys_path
2750
2751 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092752 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512753 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492754
2755
Nate Fischerdfd9812e2019-07-18 22:03:002756def _CheckPythonDevilInit(input_api, output_api):
2757 """Checks to make sure devil is initialized correctly in python scripts."""
2758 script_common_initialize_pattern = input_api.re.compile(
2759 r'script_common\.InitializeEnvironment\(')
2760 devil_env_config_initialize = input_api.re.compile(
2761 r'devil_env\.config\.Initialize\(')
2762
2763 errors = []
2764
2765 sources = lambda affected_file: input_api.FilterSourceFile(
2766 affected_file,
2767 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2768 (r'^build[\\/]android[\\/]devil_chromium\.py',
2769 r'^third_party[\\/].*',)),
2770 white_list=[r'.*\.py$'])
2771
2772 for f in input_api.AffectedSourceFiles(sources):
2773 for line_num, line in f.ChangedContents():
2774 if (script_common_initialize_pattern.search(line) or
2775 devil_env_config_initialize.search(line)):
2776 errors.append("%s:%d" % (f.LocalPath(), line_num))
2777
2778 results = []
2779
2780 if errors:
2781 results.append(output_api.PresubmitError(
2782 'Devil initialization should always be done using '
2783 'devil_chromium.Initialize() in the chromium project, to use better '
2784 'defaults for dependencies (ex. up-to-date version of adb).',
2785 errors))
2786
2787 return results
2788
2789
Sean Kau46e29bc2017-08-28 16:31:162790def _MatchesFile(input_api, patterns, path):
2791 for pattern in patterns:
2792 if input_api.re.search(pattern, path):
2793 return True
2794 return False
2795
2796
Daniel Cheng7052cdf2017-11-21 19:23:292797def _GetOwnersFilesToCheckForIpcOwners(input_api):
2798 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172799
Daniel Cheng7052cdf2017-11-21 19:23:292800 Returns:
2801 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2802 contain to cover IPC-related files with noparent reviewer rules.
2803 """
2804 # Whether or not a file affects IPC is (mostly) determined by a simple list
2805 # of filename patterns.
dchenge07de812016-06-20 19:27:172806 file_patterns = [
palmerb19a0932017-01-24 04:00:312807 # Legacy IPC:
dchenge07de812016-06-20 19:27:172808 '*_messages.cc',
2809 '*_messages*.h',
2810 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312811 # Mojo IPC:
dchenge07de812016-06-20 19:27:172812 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472813 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172814 '*_struct_traits*.*',
2815 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312816 '*.typemap',
2817 # Android native IPC:
2818 '*.aidl',
2819 # Blink uses a different file naming convention:
2820 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472821 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172822 '*StructTraits*.*',
2823 '*TypeConverter*.*',
2824 ]
2825
scottmg7a6ed5ba2016-11-04 18:22:042826 # These third_party directories do not contain IPCs, but contain files
2827 # matching the above patterns, which trigger false positives.
2828 exclude_paths = [
2829 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232830 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062831 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292832 'third_party/win_build_output/*',
Clark DuVallfb37334c2019-09-03 18:32:172833 # These aidl files are just used to communicate between class loaders
2834 # running in the same process.
2835 'weblayer/browser/java/org/chromium/weblayer_private/aidl/*',
scottmg7a6ed5ba2016-11-04 18:22:042836 ]
2837
dchenge07de812016-06-20 19:27:172838 # Dictionary mapping an OWNERS file path to Patterns.
2839 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2840 # rules ) to a PatternEntry.
2841 # PatternEntry is a dictionary with two keys:
2842 # - 'files': the files that are matched by this pattern
2843 # - 'rules': the per-file rules needed for this pattern
2844 # For example, if we expect OWNERS file to contain rules for *.mojom and
2845 # *_struct_traits*.*, Patterns might look like this:
2846 # {
2847 # '*.mojom': {
2848 # 'files': ...,
2849 # 'rules': [
2850 # 'per-file *.mojom=set noparent',
2851 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2852 # ],
2853 # },
2854 # '*_struct_traits*.*': {
2855 # 'files': ...,
2856 # 'rules': [
2857 # 'per-file *_struct_traits*.*=set noparent',
2858 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2859 # ],
2860 # },
2861 # }
2862 to_check = {}
2863
Daniel Cheng13ca61a882017-08-25 15:11:252864 def AddPatternToCheck(input_file, pattern):
2865 owners_file = input_api.os_path.join(
2866 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2867 if owners_file not in to_check:
2868 to_check[owners_file] = {}
2869 if pattern not in to_check[owners_file]:
2870 to_check[owners_file][pattern] = {
2871 'files': [],
2872 'rules': [
2873 'per-file %s=set noparent' % pattern,
2874 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2875 ]
2876 }
Vaclav Brozekd5de76a2018-03-17 07:57:502877 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252878
dchenge07de812016-06-20 19:27:172879 # Iterate through the affected files to see what we actually need to check
2880 # for. We should only nag patch authors about per-file rules if a file in that
2881 # directory would match that pattern. If a directory only contains *.mojom
2882 # files and no *_messages*.h files, we should only nag about rules for
2883 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252884 for f in input_api.AffectedFiles(include_deletes=False):
2885 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362886 # affected files for .json, .cc, and .h files which look like they contain
2887 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162888 if (f.LocalPath().endswith('.json') and
2889 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2890 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252891 json_comment_eater = _ImportJSONCommentEater(input_api)
2892 mostly_json_lines = '\n'.join(f.NewContents())
2893 # Comments aren't allowed in strict JSON, so filter them out.
2894 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432895 try:
2896 json_content = input_api.json.loads(json_lines)
2897 except:
2898 # There's another PRESUBMIT check that already verifies that JSON files
2899 # are not invalid, so no need to emit another warning here.
2900 continue
Daniel Cheng13ca61a882017-08-25 15:11:252901 if 'interface_provider_specs' in json_content:
2902 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362903 else:
2904 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2905 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2906 if (manifest_pattern.search(f.LocalPath()) and not
2907 test_manifest_pattern.search(f.LocalPath())):
2908 # We expect all actual service manifest files to contain at least one
2909 # qualified reference to service_manager::Manifest.
2910 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2911 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172912 for pattern in file_patterns:
2913 if input_api.fnmatch.fnmatch(
2914 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042915 skip = False
2916 for exclude in exclude_paths:
2917 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2918 skip = True
2919 break
2920 if skip:
2921 continue
Daniel Cheng13ca61a882017-08-25 15:11:252922 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172923 break
2924
Daniel Cheng7052cdf2017-11-21 19:23:292925 return to_check
2926
2927
2928def _CheckIpcOwners(input_api, output_api):
2929 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2930 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2931
2932 if to_check:
2933 # If there are any OWNERS files to check, there are IPC-related changes in
2934 # this CL. Auto-CC the review list.
2935 output_api.AppendCC('[email protected]')
2936
2937 # Go through the OWNERS files to check, filtering out rules that are already
2938 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172939 for owners_file, patterns in to_check.iteritems():
2940 try:
2941 with file(owners_file) as f:
2942 lines = set(f.read().splitlines())
2943 for entry in patterns.itervalues():
2944 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2945 ]
2946 except IOError:
2947 # No OWNERS file, so all the rules are definitely missing.
2948 continue
2949
2950 # All the remaining lines weren't found in OWNERS files, so emit an error.
2951 errors = []
2952 for owners_file, patterns in to_check.iteritems():
2953 missing_lines = []
2954 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502955 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172956 missing_lines.extend(entry['rules'])
2957 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2958 if missing_lines:
2959 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052960 'Because of the presence of files:\n%s\n\n'
2961 '%s needs the following %d lines added:\n\n%s' %
2962 ('\n'.join(files), owners_file, len(missing_lines),
2963 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172964
2965 results = []
2966 if errors:
vabrf5ce3bf92016-07-11 14:52:412967 if input_api.is_committing:
2968 output = output_api.PresubmitError
2969 else:
2970 output = output_api.PresubmitPromptWarning
2971 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592972 'Found OWNERS files that need to be updated for IPC security ' +
2973 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172974 long_text='\n\n'.join(errors)))
2975
2976 return results
2977
2978
jbriance9e12f162016-11-25 07:57:502979def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312980 """Checks that added or removed lines in non third party affected
2981 header files do not lead to new useless class or struct forward
2982 declaration.
jbriance9e12f162016-11-25 07:57:502983 """
2984 results = []
2985 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2986 input_api.re.MULTILINE)
2987 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2988 input_api.re.MULTILINE)
2989 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312990 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192991 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492992 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312993 continue
2994
jbriance9e12f162016-11-25 07:57:502995 if not f.LocalPath().endswith('.h'):
2996 continue
2997
2998 contents = input_api.ReadFile(f)
2999 fwd_decls = input_api.re.findall(class_pattern, contents)
3000 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3001
3002 useless_fwd_decls = []
3003 for decl in fwd_decls:
3004 count = sum(1 for _ in input_api.re.finditer(
3005 r'\b%s\b' % input_api.re.escape(decl), contents))
3006 if count == 1:
3007 useless_fwd_decls.append(decl)
3008
3009 if not useless_fwd_decls:
3010 continue
3011
3012 for line in f.GenerateScmDiff().splitlines():
3013 if (line.startswith('-') and not line.startswith('--') or
3014 line.startswith('+') and not line.startswith('++')):
3015 for decl in useless_fwd_decls:
3016 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3017 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243018 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503019 (f.LocalPath(), decl)))
3020 useless_fwd_decls.remove(decl)
3021
3022 return results
3023
Jinsong Fan91ebbbd2019-04-16 14:57:173024def _CheckAndroidDebuggableBuild(input_api, output_api):
3025 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3026 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3027 this is a debuggable build of Android.
3028 """
3029 build_type_check_pattern = input_api.re.compile(
3030 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3031
3032 errors = []
3033
3034 sources = lambda affected_file: input_api.FilterSourceFile(
3035 affected_file,
3036 black_list=(_EXCLUDED_PATHS +
3037 _TEST_CODE_EXCLUDED_PATHS +
3038 input_api.DEFAULT_BLACK_LIST +
3039 (r"^android_webview[\\/]support_library[\\/]"
3040 "boundary_interfaces[\\/]",
3041 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3042 r'^third_party[\\/].*',
3043 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3044 r"webview[\\/]chromium[\\/]License.*",)),
3045 white_list=[r'.*\.java$'])
3046
3047 for f in input_api.AffectedSourceFiles(sources):
3048 for line_num, line in f.ChangedContents():
3049 if build_type_check_pattern.search(line):
3050 errors.append("%s:%d" % (f.LocalPath(), line_num))
3051
3052 results = []
3053
3054 if errors:
3055 results.append(output_api.PresubmitPromptWarning(
3056 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3057 ' Please use BuildInfo.isDebugAndroid() instead.',
3058 errors))
3059
3060 return results
jbriance9e12f162016-11-25 07:57:503061
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493062# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293063def _CheckAndroidToastUsage(input_api, output_api):
3064 """Checks that code uses org.chromium.ui.widget.Toast instead of
3065 android.widget.Toast (Chromium Toast doesn't force hardware
3066 acceleration on low-end devices, saving memory).
3067 """
3068 toast_import_pattern = input_api.re.compile(
3069 r'^import android\.widget\.Toast;$')
3070
3071 errors = []
3072
3073 sources = lambda affected_file: input_api.FilterSourceFile(
3074 affected_file,
3075 black_list=(_EXCLUDED_PATHS +
3076 _TEST_CODE_EXCLUDED_PATHS +
3077 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043078 (r'^chromecast[\\/].*',
3079 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493080 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293081
3082 for f in input_api.AffectedSourceFiles(sources):
3083 for line_num, line in f.ChangedContents():
3084 if toast_import_pattern.search(line):
3085 errors.append("%s:%d" % (f.LocalPath(), line_num))
3086
3087 results = []
3088
3089 if errors:
3090 results.append(output_api.PresubmitError(
3091 'android.widget.Toast usage is detected. Android toasts use hardware'
3092 ' acceleration, and can be\ncostly on low-end devices. Please use'
3093 ' org.chromium.ui.widget.Toast instead.\n'
3094 'Contact [email protected] if you have any questions.',
3095 errors))
3096
3097 return results
3098
3099
dgnaa68d5e2015-06-10 10:08:223100def _CheckAndroidCrLogUsage(input_api, output_api):
3101 """Checks that new logs using org.chromium.base.Log:
3102 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513103 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223104 """
pkotwicza1dd0b002016-05-16 14:41:043105
torne89540622017-03-24 19:41:303106 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043107 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303108 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043109 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303110 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043111 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3112 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093113 # The customtabs_benchmark is a small app that does not depend on Chromium
3114 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043115 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043116 ]
3117
dgnaa68d5e2015-06-10 10:08:223118 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123119 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3120 class_in_base_pattern = input_api.re.compile(
3121 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3122 has_some_log_import_pattern = input_api.re.compile(
3123 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223124 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:123125 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:223126 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463127 r'static final String TAG = "(?P<name>(.*))"')
dgnaa68d5e2015-06-10 10:08:223128
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463129 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493130 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043131 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123132
dgnaa68d5e2015-06-10 10:08:223133 tag_decl_errors = []
3134 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123135 tag_errors = []
dgn38736db2015-09-18 19:20:513136 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123137 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223138
3139 for f in input_api.AffectedSourceFiles(sources):
3140 file_content = input_api.ReadFile(f)
3141 has_modified_logs = False
3142
3143 # Per line checks
dgn87d9fb62015-06-12 09:15:123144 if (cr_log_import_pattern.search(file_content) or
3145 (class_in_base_pattern.search(file_content) and
3146 not has_some_log_import_pattern.search(file_content))):
3147 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223148 for line_num, line in f.ChangedContents():
3149
3150 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123151 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223152 if match:
3153 has_modified_logs = True
3154
3155 # Make sure it uses "TAG"
3156 if not match.group('tag') == 'TAG':
3157 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123158 else:
3159 # Report non cr Log function calls in changed lines
3160 for line_num, line in f.ChangedContents():
3161 if log_call_pattern.search(line):
3162 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223163
3164 # Per file checks
3165 if has_modified_logs:
3166 # Make sure the tag is using the "cr" prefix and is not too long
3167 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513168 tag_name = match.group('name') if match else None
3169 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223170 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513171 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223172 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513173 elif '.' in tag_name:
3174 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223175
3176 results = []
3177 if tag_decl_errors:
3178 results.append(output_api.PresubmitPromptWarning(
3179 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513180 '"private static final String TAG = "<package tag>".\n'
3181 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223182 tag_decl_errors))
3183
3184 if tag_length_errors:
3185 results.append(output_api.PresubmitError(
3186 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513187 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223188 tag_length_errors))
3189
3190 if tag_errors:
3191 results.append(output_api.PresubmitPromptWarning(
3192 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3193 tag_errors))
3194
dgn87d9fb62015-06-12 09:15:123195 if util_log_errors:
dgn4401aa52015-04-29 16:26:173196 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123197 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3198 util_log_errors))
3199
dgn38736db2015-09-18 19:20:513200 if tag_with_dot_errors:
3201 results.append(output_api.PresubmitPromptWarning(
3202 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3203 tag_with_dot_errors))
3204
dgn4401aa52015-04-29 16:26:173205 return results
3206
3207
Yoland Yanb92fa522017-08-28 17:37:063208def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3209 """Checks that junit.framework.* is no longer used."""
3210 deprecated_junit_framework_pattern = input_api.re.compile(
3211 r'^import junit\.framework\..*;',
3212 input_api.re.MULTILINE)
3213 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493214 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063215 errors = []
3216 for f in input_api.AffectedFiles(sources):
3217 for line_num, line in f.ChangedContents():
3218 if deprecated_junit_framework_pattern.search(line):
3219 errors.append("%s:%d" % (f.LocalPath(), line_num))
3220
3221 results = []
3222 if errors:
3223 results.append(output_api.PresubmitError(
3224 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3225 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3226 ' if you have any question.', errors))
3227 return results
3228
3229
3230def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3231 """Checks that if new Java test classes have inheritance.
3232 Either the new test class is JUnit3 test or it is a JUnit4 test class
3233 with a base class, either case is undesirable.
3234 """
3235 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3236
3237 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493238 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063239 errors = []
3240 for f in input_api.AffectedFiles(sources):
3241 if not f.OldContents():
3242 class_declaration_start_flag = False
3243 for line_num, line in f.ChangedContents():
3244 if class_declaration_pattern.search(line):
3245 class_declaration_start_flag = True
3246 if class_declaration_start_flag and ' extends ' in line:
3247 errors.append('%s:%d' % (f.LocalPath(), line_num))
3248 if '{' in line:
3249 class_declaration_start_flag = False
3250
3251 results = []
3252 if errors:
3253 results.append(output_api.PresubmitPromptWarning(
3254 'The newly created files include Test classes that inherits from base'
3255 ' class. Please do not use inheritance in JUnit4 tests or add new'
3256 ' JUnit3 tests. Contact [email protected] if you have any'
3257 ' questions.', errors))
3258 return results
3259
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203260
yolandyan45001472016-12-21 21:12:423261def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3262 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3263 deprecated_annotation_import_pattern = input_api.re.compile(
3264 r'^import android\.test\.suitebuilder\.annotation\..*;',
3265 input_api.re.MULTILINE)
3266 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493267 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423268 errors = []
3269 for f in input_api.AffectedFiles(sources):
3270 for line_num, line in f.ChangedContents():
3271 if deprecated_annotation_import_pattern.search(line):
3272 errors.append("%s:%d" % (f.LocalPath(), line_num))
3273
3274 results = []
3275 if errors:
3276 results.append(output_api.PresubmitError(
3277 'Annotations in android.test.suitebuilder.annotation have been'
3278 ' deprecated since API level 24. Please use android.support.test.filters'
3279 ' from //third_party/android_support_test_runner:runner_java instead.'
3280 ' Contact [email protected] if you have any questions.', errors))
3281 return results
3282
3283
agrieve7b6479d82015-10-07 14:24:223284def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3285 """Checks if MDPI assets are placed in a correct directory."""
3286 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3287 ('/res/drawable/' in f.LocalPath() or
3288 '/res/drawable-ldrtl/' in f.LocalPath()))
3289 errors = []
3290 for f in input_api.AffectedFiles(include_deletes=False,
3291 file_filter=file_filter):
3292 errors.append(' %s' % f.LocalPath())
3293
3294 results = []
3295 if errors:
3296 results.append(output_api.PresubmitError(
3297 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3298 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3299 '/res/drawable-ldrtl/.\n'
3300 'Contact [email protected] if you have questions.', errors))
3301 return results
3302
3303
Nate Fischer535972b2017-09-16 01:06:183304def _CheckAndroidWebkitImports(input_api, output_api):
3305 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353306 android.webview.ValueCallback except in the WebView glue layer
3307 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183308 """
3309 valuecallback_import_pattern = input_api.re.compile(
3310 r'^import android\.webkit\.ValueCallback;$')
3311
3312 errors = []
3313
3314 sources = lambda affected_file: input_api.FilterSourceFile(
3315 affected_file,
3316 black_list=(_EXCLUDED_PATHS +
3317 _TEST_CODE_EXCLUDED_PATHS +
3318 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353319 (r'^android_webview[\\/]glue[\\/].*',
3320 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493321 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183322
3323 for f in input_api.AffectedSourceFiles(sources):
3324 for line_num, line in f.ChangedContents():
3325 if valuecallback_import_pattern.search(line):
3326 errors.append("%s:%d" % (f.LocalPath(), line_num))
3327
3328 results = []
3329
3330 if errors:
3331 results.append(output_api.PresubmitError(
3332 'android.webkit.ValueCallback usage is detected outside of the glue'
3333 ' layer. To stay compatible with the support library, android.webkit.*'
3334 ' classes should only be used inside the glue layer and'
3335 ' org.chromium.base.Callback should be used instead.',
3336 errors))
3337
3338 return results
3339
3340
Becky Zhou7c69b50992018-12-10 19:37:573341def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3342 """Checks Android XML styles """
3343 import sys
3344 original_sys_path = sys.path
3345 try:
3346 sys.path = sys.path + [input_api.os_path.join(
3347 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3348 import checkxmlstyle
3349 finally:
3350 # Restore sys.path to what it was before.
3351 sys.path = original_sys_path
3352
3353 if is_check_on_upload:
3354 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3355 else:
3356 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3357
3358
agrievef32bcc72016-04-04 14:57:403359class PydepsChecker(object):
3360 def __init__(self, input_api, pydeps_files):
3361 self._file_cache = {}
3362 self._input_api = input_api
3363 self._pydeps_files = pydeps_files
3364
3365 def _LoadFile(self, path):
3366 """Returns the list of paths within a .pydeps file relative to //."""
3367 if path not in self._file_cache:
3368 with open(path) as f:
3369 self._file_cache[path] = f.read()
3370 return self._file_cache[path]
3371
3372 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3373 """Returns an interable of paths within the .pydep, relativized to //."""
3374 os_path = self._input_api.os_path
3375 pydeps_dir = os_path.dirname(pydeps_path)
3376 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3377 if not l.startswith('*'))
3378 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3379
3380 def _CreateFilesToPydepsMap(self):
3381 """Returns a map of local_path -> list_of_pydeps."""
3382 ret = {}
3383 for pydep_local_path in self._pydeps_files:
3384 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3385 ret.setdefault(path, []).append(pydep_local_path)
3386 return ret
3387
3388 def ComputeAffectedPydeps(self):
3389 """Returns an iterable of .pydeps files that might need regenerating."""
3390 affected_pydeps = set()
3391 file_to_pydeps_map = None
3392 for f in self._input_api.AffectedFiles(include_deletes=True):
3393 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463394 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3395 # subrepositories. We can't figure out which files change, so re-check
3396 # all files.
3397 # Changes to print_python_deps.py affect all .pydeps.
3398 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403399 return self._pydeps_files
3400 elif local_path.endswith('.pydeps'):
3401 if local_path in self._pydeps_files:
3402 affected_pydeps.add(local_path)
3403 elif local_path.endswith('.py'):
3404 if file_to_pydeps_map is None:
3405 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3406 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3407 return affected_pydeps
3408
3409 def DetermineIfStale(self, pydeps_path):
3410 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413411 import difflib
John Budorick47ca3fe2018-02-10 00:53:103412 import os
3413
agrievef32bcc72016-04-04 14:57:403414 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3415 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103416 env = dict(os.environ)
3417 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403418 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103419 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413420 old_contents = old_pydeps_data[2:]
3421 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403422 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413423 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403424
3425
Tibor Goldschwendt360793f72019-06-25 18:23:493426def _ParseGclientArgs():
3427 args = {}
3428 with open('build/config/gclient_args.gni', 'r') as f:
3429 for line in f:
3430 line = line.strip()
3431 if not line or line.startswith('#'):
3432 continue
3433 attribute, value = line.split('=')
3434 args[attribute.strip()] = value.strip()
3435 return args
3436
3437
agrievef32bcc72016-04-04 14:57:403438def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3439 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403440 # This check is for Python dependency lists (.pydeps files), and involves
3441 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3442 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283443 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003444 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493445 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403446 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3447 results = []
3448 # First, check for new / deleted .pydeps.
3449 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033450 # Check whether we are running the presubmit check for a file in src.
3451 # f.LocalPath is relative to repo (src, or internal repo).
3452 # os_path.exists is relative to src repo.
3453 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3454 # to src and we can conclude that the pydeps is in src.
3455 if input_api.os_path.exists(f.LocalPath()):
3456 if f.LocalPath().endswith('.pydeps'):
3457 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3458 results.append(output_api.PresubmitError(
3459 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3460 'remove %s' % f.LocalPath()))
3461 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3462 results.append(output_api.PresubmitError(
3463 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3464 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403465
3466 if results:
3467 return results
3468
3469 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3470
3471 for pydep_path in checker.ComputeAffectedPydeps():
3472 try:
phajdan.jr0d9878552016-11-04 10:49:413473 result = checker.DetermineIfStale(pydep_path)
3474 if result:
3475 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403476 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413477 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3478 'To regenerate, run:\n\n %s' %
3479 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403480 except input_api.subprocess.CalledProcessError as error:
3481 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3482 long_text=error.output)]
3483
3484 return results
3485
3486
glidere61efad2015-02-18 17:39:433487def _CheckSingletonInHeaders(input_api, output_api):
3488 """Checks to make sure no header files have |Singleton<|."""
3489 def FileFilter(affected_file):
3490 # It's ok for base/memory/singleton.h to have |Singleton<|.
3491 black_list = (_EXCLUDED_PATHS +
3492 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043493 (r"^base[\\/]memory[\\/]singleton\.h$",
3494 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473495 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433496 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3497
sergeyu34d21222015-09-16 00:11:443498 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433499 files = []
3500 for f in input_api.AffectedSourceFiles(FileFilter):
3501 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3502 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3503 contents = input_api.ReadFile(f)
3504 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243505 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433506 pattern.search(line)):
3507 files.append(f)
3508 break
3509
3510 if files:
yolandyandaabc6d2016-04-18 18:29:393511 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443512 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433513 'Please move them to an appropriate source file so that the ' +
3514 'template gets instantiated in a single compilation unit.',
3515 files) ]
3516 return []
3517
3518
[email protected]fd20b902014-05-09 02:14:533519_DEPRECATED_CSS = [
3520 # Values
3521 ( "-webkit-box", "flex" ),
3522 ( "-webkit-inline-box", "inline-flex" ),
3523 ( "-webkit-flex", "flex" ),
3524 ( "-webkit-inline-flex", "inline-flex" ),
3525 ( "-webkit-min-content", "min-content" ),
3526 ( "-webkit-max-content", "max-content" ),
3527
3528 # Properties
3529 ( "-webkit-background-clip", "background-clip" ),
3530 ( "-webkit-background-origin", "background-origin" ),
3531 ( "-webkit-background-size", "background-size" ),
3532 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443533 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533534
3535 # Functions
3536 ( "-webkit-gradient", "gradient" ),
3537 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3538 ( "-webkit-linear-gradient", "linear-gradient" ),
3539 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3540 ( "-webkit-radial-gradient", "radial-gradient" ),
3541 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3542]
3543
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203544
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493545# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243546def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533547 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253548 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343549 documentation and iOS CSS for dom distiller
3550 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253551 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533552 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493553 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253554 black_list = (_EXCLUDED_PATHS +
3555 _TEST_CODE_EXCLUDED_PATHS +
3556 input_api.DEFAULT_BLACK_LIST +
3557 (r"^chrome/common/extensions/docs",
3558 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343559 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443560 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253561 r"^native_client_sdk"))
3562 file_filter = lambda f: input_api.FilterSourceFile(
3563 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533564 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3565 for line_num, line in fpath.ChangedContents():
3566 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023567 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533568 results.append(output_api.PresubmitError(
3569 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3570 (fpath.LocalPath(), line_num, deprecated_value, value)))
3571 return results
3572
mohan.reddyf21db962014-10-16 12:26:473573
rlanday6802cf632017-05-30 17:48:363574def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363575 bad_files = {}
3576 for f in input_api.AffectedFiles(include_deletes=False):
3577 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493578 not f.LocalPath().startswith('third_party/blink') and
3579 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363580 continue
3581
Daniel Bratell65b033262019-04-23 08:17:063582 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363583 continue
3584
Vaclav Brozekd5de76a2018-03-17 07:57:503585 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363586 if "#include" in line and "../" in line]
3587 if not relative_includes:
3588 continue
3589 bad_files[f.LocalPath()] = relative_includes
3590
3591 if not bad_files:
3592 return []
3593
3594 error_descriptions = []
3595 for file_path, bad_lines in bad_files.iteritems():
3596 error_description = file_path
3597 for line in bad_lines:
3598 error_description += '\n ' + line
3599 error_descriptions.append(error_description)
3600
3601 results = []
3602 results.append(output_api.PresubmitError(
3603 'You added one or more relative #include paths (including "../").\n'
3604 'These shouldn\'t be used because they can be used to include headers\n'
3605 'from code that\'s not correctly specified as a dependency in the\n'
3606 'relevant BUILD.gn file(s).',
3607 error_descriptions))
3608
3609 return results
3610
Takeshi Yoshinoe387aa32017-08-02 13:16:133611
Daniel Bratell65b033262019-04-23 08:17:063612def _CheckForCcIncludes(input_api, output_api):
3613 """Check that nobody tries to include a cc file. It's a relatively
3614 common error which results in duplicate symbols in object
3615 files. This may not always break the build until someone later gets
3616 very confusing linking errors."""
3617 results = []
3618 for f in input_api.AffectedFiles(include_deletes=False):
3619 # We let third_party code do whatever it wants
3620 if (f.LocalPath().startswith('third_party') and
3621 not f.LocalPath().startswith('third_party/blink') and
3622 not f.LocalPath().startswith('third_party\\blink')):
3623 continue
3624
3625 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3626 continue
3627
3628 for _, line in f.ChangedContents():
3629 if line.startswith('#include "'):
3630 included_file = line.split('"')[1]
3631 if _IsCPlusPlusFile(input_api, included_file):
3632 # The most common naming for external files with C++ code,
3633 # apart from standard headers, is to call them foo.inc, but
3634 # Chromium sometimes uses foo-inc.cc so allow that as well.
3635 if not included_file.endswith(('.h', '-inc.cc')):
3636 results.append(output_api.PresubmitError(
3637 'Only header files or .inc files should be included in other\n'
3638 'C++ files. Compiling the contents of a cc file more than once\n'
3639 'will cause duplicate information in the build which may later\n'
3640 'result in strange link_errors.\n' +
3641 f.LocalPath() + ':\n ' +
3642 line))
3643
3644 return results
3645
3646
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203647def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3648 if not isinstance(key, ast.Str):
3649 return 'Key at line %d must be a string literal' % key.lineno
3650 if not isinstance(value, ast.Dict):
3651 return 'Value at line %d must be a dict' % value.lineno
3652 if len(value.keys) != 1:
3653 return 'Dict at line %d must have single entry' % value.lineno
3654 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3655 return (
3656 'Entry at line %d must have a string literal \'filepath\' as key' %
3657 value.lineno)
3658 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133659
Takeshi Yoshinoe387aa32017-08-02 13:16:133660
Sergey Ulanov4af16052018-11-08 02:41:463661def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203662 if not isinstance(key, ast.Str):
3663 return 'Key at line %d must be a string literal' % key.lineno
3664 if not isinstance(value, ast.List):
3665 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463666 for element in value.elts:
3667 if not isinstance(element, ast.Str):
3668 return 'Watchlist elements on line %d is not a string' % key.lineno
3669 if not email_regex.match(element.s):
3670 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3671 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203672 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133673
Takeshi Yoshinoe387aa32017-08-02 13:16:133674
Sergey Ulanov4af16052018-11-08 02:41:463675def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203676 mismatch_template = (
3677 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3678 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133679
Sergey Ulanov4af16052018-11-08 02:41:463680 email_regex = input_api.re.compile(
3681 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3682
3683 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203684 i = 0
3685 last_key = ''
3686 while True:
3687 if i >= len(wd_dict.keys):
3688 if i >= len(w_dict.keys):
3689 return None
3690 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3691 elif i >= len(w_dict.keys):
3692 return (
3693 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133694
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203695 wd_key = wd_dict.keys[i]
3696 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133697
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203698 result = _CheckWatchlistDefinitionsEntrySyntax(
3699 wd_key, wd_dict.values[i], ast)
3700 if result is not None:
3701 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133702
Sergey Ulanov4af16052018-11-08 02:41:463703 result = _CheckWatchlistsEntrySyntax(
3704 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203705 if result is not None:
3706 return 'Bad entry in WATCHLISTS dict: %s' % result
3707
3708 if wd_key.s != w_key.s:
3709 return mismatch_template % (
3710 '%s at line %d' % (wd_key.s, wd_key.lineno),
3711 '%s at line %d' % (w_key.s, w_key.lineno))
3712
3713 if wd_key.s < last_key:
3714 return (
3715 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3716 (wd_key.lineno, w_key.lineno))
3717 last_key = wd_key.s
3718
3719 i = i + 1
3720
3721
Sergey Ulanov4af16052018-11-08 02:41:463722def _CheckWATCHLISTSSyntax(expression, input_api):
3723 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203724 if not isinstance(expression, ast.Expression):
3725 return 'WATCHLISTS file must contain a valid expression'
3726 dictionary = expression.body
3727 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3728 return 'WATCHLISTS file must have single dict with exactly two entries'
3729
3730 first_key = dictionary.keys[0]
3731 first_value = dictionary.values[0]
3732 second_key = dictionary.keys[1]
3733 second_value = dictionary.values[1]
3734
3735 if (not isinstance(first_key, ast.Str) or
3736 first_key.s != 'WATCHLIST_DEFINITIONS' or
3737 not isinstance(first_value, ast.Dict)):
3738 return (
3739 'The first entry of the dict in WATCHLISTS file must be '
3740 'WATCHLIST_DEFINITIONS dict')
3741
3742 if (not isinstance(second_key, ast.Str) or
3743 second_key.s != 'WATCHLISTS' or
3744 not isinstance(second_value, ast.Dict)):
3745 return (
3746 'The second entry of the dict in WATCHLISTS file must be '
3747 'WATCHLISTS dict')
3748
Sergey Ulanov4af16052018-11-08 02:41:463749 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133750
3751
3752def _CheckWATCHLISTS(input_api, output_api):
3753 for f in input_api.AffectedFiles(include_deletes=False):
3754 if f.LocalPath() == 'WATCHLISTS':
3755 contents = input_api.ReadFile(f, 'r')
3756
3757 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203758 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133759 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203760 # Get an AST tree for it and scan the tree for detailed style checking.
3761 expression = input_api.ast.parse(
3762 contents, filename='WATCHLISTS', mode='eval')
3763 except ValueError as e:
3764 return [output_api.PresubmitError(
3765 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3766 except SyntaxError as e:
3767 return [output_api.PresubmitError(
3768 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3769 except TypeError as e:
3770 return [output_api.PresubmitError(
3771 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133772
Sergey Ulanov4af16052018-11-08 02:41:463773 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203774 if result is not None:
3775 return [output_api.PresubmitError(result)]
3776 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133777
3778 return []
3779
3780
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193781def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3782 """Checks that newly added header files have corresponding GN changes.
3783 Note that this is only a heuristic. To be precise, run script:
3784 build/check_gn_headers.py.
3785 """
3786
3787 def headers(f):
3788 return input_api.FilterSourceFile(
3789 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3790
3791 new_headers = []
3792 for f in input_api.AffectedSourceFiles(headers):
3793 if f.Action() != 'A':
3794 continue
3795 new_headers.append(f.LocalPath())
3796
3797 def gn_files(f):
3798 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3799
3800 all_gn_changed_contents = ''
3801 for f in input_api.AffectedSourceFiles(gn_files):
3802 for _, line in f.ChangedContents():
3803 all_gn_changed_contents += line
3804
3805 problems = []
3806 for header in new_headers:
3807 basename = input_api.os_path.basename(header)
3808 if basename not in all_gn_changed_contents:
3809 problems.append(header)
3810
3811 if problems:
3812 return [output_api.PresubmitPromptWarning(
3813 'Missing GN changes for new header files', items=sorted(problems),
3814 long_text='Please double check whether newly added header files need '
3815 'corresponding changes in gn or gni files.\nThis checking is only a '
3816 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3817 'Read https://crbug.com/661774 for more info.')]
3818 return []
3819
3820
Michael Giuffridad3bc8672018-10-25 22:48:023821def _CheckCorrectProductNameInMessages(input_api, output_api):
3822 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3823
3824 This assumes we won't intentionally reference one product from the other
3825 product.
3826 """
3827 all_problems = []
3828 test_cases = [{
3829 "filename_postfix": "google_chrome_strings.grd",
3830 "correct_name": "Chrome",
3831 "incorrect_name": "Chromium",
3832 }, {
3833 "filename_postfix": "chromium_strings.grd",
3834 "correct_name": "Chromium",
3835 "incorrect_name": "Chrome",
3836 }]
3837
3838 for test_case in test_cases:
3839 problems = []
3840 filename_filter = lambda x: x.LocalPath().endswith(
3841 test_case["filename_postfix"])
3842
3843 # Check each new line. Can yield false positives in multiline comments, but
3844 # easier than trying to parse the XML because messages can have nested
3845 # children, and associating message elements with affected lines is hard.
3846 for f in input_api.AffectedSourceFiles(filename_filter):
3847 for line_num, line in f.ChangedContents():
3848 if "<message" in line or "<!--" in line or "-->" in line:
3849 continue
3850 if test_case["incorrect_name"] in line:
3851 problems.append(
3852 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3853
3854 if problems:
3855 message = (
3856 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3857 % (test_case["correct_name"], test_case["correct_name"],
3858 test_case["incorrect_name"]))
3859 all_problems.append(
3860 output_api.PresubmitPromptWarning(message, items=problems))
3861
3862 return all_problems
3863
3864
Dirk Pranke3c18a382019-03-15 01:07:513865def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3866 # TODO(crbug.com/941824): We need to make sure the entries in
3867 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3868 # so that users of //buildtools in other projects get the same tooling
3869 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3870 # support to gclient, we can eliminate the duplication and delete
3871 # this presubmit check.
3872
3873 # Update this regexp if new revisions are added to the files.
3874 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013875 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513876
3877 # If a user is changing one revision, they need to change the same
3878 # line in both files. This means that any given change should contain
3879 # exactly the same list of changed lines that match the regexps. The
3880 # replace(' ', '') call allows us to ignore whitespace changes to the
3881 # lines. The 'long_text' parameter to the error will contain the
3882 # list of changed lines in both files, which should make it easy enough
3883 # to spot the error without going overboard in this implementation.
3884 revs_changes = {
3885 'DEPS': {},
3886 'buildtools/DEPS': {},
3887 }
3888 long_text = ''
3889
3890 for f in input_api.AffectedFiles(
3891 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3892 for line_num, line in f.ChangedContents():
3893 if rev_regexp.search(line):
3894 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3895 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3896
3897 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3898 return [output_api.PresubmitError(
3899 'Change buildtools revisions in sync in both //DEPS and '
3900 '//buildtools/DEPS.', long_text=long_text + '\n')]
3901 else:
3902 return []
3903
3904
Daniel Bratell93eb6c62019-04-29 20:13:363905def _CheckForTooLargeFiles(input_api, output_api):
3906 """Avoid large files, especially binary files, in the repository since
3907 git doesn't scale well for those. They will be in everyone's repo
3908 clones forever, forever making Chromium slower to clone and work
3909 with."""
3910
3911 # Uploading files to cloud storage is not trivial so we don't want
3912 # to set the limit too low, but the upper limit for "normal" large
3913 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3914 # anything over 20 MB is exceptional.
3915 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3916
3917 too_large_files = []
3918 for f in input_api.AffectedFiles():
3919 # Check both added and modified files (but not deleted files).
3920 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383921 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363922 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3923 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3924
3925 if too_large_files:
3926 message = (
3927 'Do not commit large files to git since git scales badly for those.\n' +
3928 'Instead put the large files in cloud storage and use DEPS to\n' +
3929 'fetch them.\n' + '\n'.join(too_large_files)
3930 )
3931 return [output_api.PresubmitError(
3932 'Too large files found in commit', long_text=message + '\n')]
3933 else:
3934 return []
3935
Max Morozb47503b2019-08-08 21:03:273936
3937def _CheckFuzzTargets(input_api, output_api):
3938 """Checks specific for fuzz target sources."""
3939 EXPORTED_SYMBOLS = [
3940 'LLVMFuzzerInitialize',
3941 'LLVMFuzzerCustomMutator',
3942 'LLVMFuzzerCustomCrossOver',
3943 'LLVMFuzzerMutate',
3944 ]
3945
3946 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3947
3948 def FilterFile(affected_file):
3949 """Ignore libFuzzer source code."""
3950 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
3951 black_list = r"^third_party[\\/]libFuzzer"
3952
3953 return input_api.FilterSourceFile(
3954 affected_file,
3955 white_list=[white_list],
3956 black_list=[black_list])
3957
3958 files_with_missing_header = []
3959 for f in input_api.AffectedSourceFiles(FilterFile):
3960 contents = input_api.ReadFile(f, 'r')
3961 if REQUIRED_HEADER in contents:
3962 continue
3963
3964 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
3965 files_with_missing_header.append(f.LocalPath())
3966
3967 if not files_with_missing_header:
3968 return []
3969
3970 long_text = (
3971 'If you define any of the libFuzzer optional functions (%s), it is '
3972 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
3973 'work incorrectly on Mac (crbug.com/687076).\nNote that '
3974 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
3975 'to access command line arguments passed to the fuzzer. Instead, prefer '
3976 'static initialization and shared resources as documented in '
3977 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
3978 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
3979 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
3980 )
3981
3982 return [output_api.PresubmitPromptWarning(
3983 message="Missing '%s' in:" % REQUIRED_HEADER,
3984 items=files_with_missing_header,
3985 long_text=long_text)]
3986
3987
dgnaa68d5e2015-06-10 10:08:223988def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573989 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223990 results = []
dgnaa68d5e2015-06-10 10:08:223991 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173992 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223993 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293994 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063995 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3996 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423997 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183998 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573999 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4000 return results
4001
4002def _AndroidSpecificOnCommitChecks(input_api, output_api):
4003 """Groups commit checks that target android code."""
4004 results = []
4005 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224006 return results
4007
4008
[email protected]22c9bd72011-03-27 16:47:394009def _CommonChecks(input_api, output_api):
4010 """Checks common to both upload and commit."""
4011 results = []
4012 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384013 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544014 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084015
4016 author = input_api.change.author_email
4017 if author and author not in _KNOWN_ROBOTS:
4018 results.extend(
4019 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4020
[email protected]55459852011-08-10 15:17:194021 results.extend(
[email protected]760deea2013-12-10 19:33:494022 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234023 results.extend(
4024 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544025 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184026 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344027 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524028 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224029 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444030 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594031 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314032 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064033 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124034 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184035 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224036 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304037 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494038 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034039 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494040 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444041 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274042 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074043 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544044 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444045 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394046 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554047 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044048 results.extend(
4049 input_api.canned_checks.CheckChangeHasNoTabs(
4050 input_api,
4051 output_api,
4052 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404053 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164054 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084055 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244056 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474057 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044058 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054059 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144060 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234061 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434062 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404063 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154064 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:174065 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504066 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364067 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064068 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134069 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434070 results.extend(input_api.RunTests(
4071 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144072 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024073 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514074 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364075 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004076 results.extend(_CheckPythonDevilInit(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244077
Vaclav Brozekcdc7defb2018-03-20 09:54:354078 for f in input_api.AffectedFiles():
4079 path, name = input_api.os_path.split(f.LocalPath())
4080 if name == 'PRESUBMIT.py':
4081 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004082 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4083 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074084 # The PRESUBMIT.py file (and the directory containing it) might
4085 # have been affected by being moved or removed, so only try to
4086 # run the tests if they still exist.
4087 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4088 input_api, output_api, full_path,
4089 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394090 return results
[email protected]1f7b4172010-01-28 01:17:344091
[email protected]b337cb5b2011-01-23 21:24:054092
[email protected]b8079ae4a2012-12-05 19:56:494093def _CheckPatchFiles(input_api, output_api):
4094 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4095 if f.LocalPath().endswith(('.orig', '.rej'))]
4096 if problems:
4097 return [output_api.PresubmitError(
4098 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034099 else:
4100 return []
[email protected]b8079ae4a2012-12-05 19:56:494101
4102
Kent Tamura5a8755d2017-06-29 23:37:074103def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214104 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4105 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4106 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074107 include_re = input_api.re.compile(
4108 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4109 extension_re = input_api.re.compile(r'\.[a-z]+$')
4110 errors = []
4111 for f in input_api.AffectedFiles():
4112 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4113 continue
4114 found_line_number = None
4115 found_macro = None
4116 for line_num, line in f.ChangedContents():
4117 match = macro_re.search(line)
4118 if match:
4119 found_line_number = line_num
4120 found_macro = match.group(2)
4121 break
4122 if not found_line_number:
4123 continue
4124
4125 found_include = False
4126 for line in f.NewContents():
4127 if include_re.search(line):
4128 found_include = True
4129 break
4130 if found_include:
4131 continue
4132
4133 if not f.LocalPath().endswith('.h'):
4134 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4135 try:
4136 content = input_api.ReadFile(primary_header_path, 'r')
4137 if include_re.search(content):
4138 continue
4139 except IOError:
4140 pass
4141 errors.append('%s:%d %s macro is used without including build/'
4142 'build_config.h.'
4143 % (f.LocalPath(), found_line_number, found_macro))
4144 if errors:
4145 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4146 return []
4147
4148
[email protected]b00342e7f2013-03-26 16:21:544149def _DidYouMeanOSMacro(bad_macro):
4150 try:
4151 return {'A': 'OS_ANDROID',
4152 'B': 'OS_BSD',
4153 'C': 'OS_CHROMEOS',
4154 'F': 'OS_FREEBSD',
4155 'L': 'OS_LINUX',
4156 'M': 'OS_MACOSX',
4157 'N': 'OS_NACL',
4158 'O': 'OS_OPENBSD',
4159 'P': 'OS_POSIX',
4160 'S': 'OS_SOLARIS',
4161 'W': 'OS_WIN'}[bad_macro[3].upper()]
4162 except KeyError:
4163 return ''
4164
4165
4166def _CheckForInvalidOSMacrosInFile(input_api, f):
4167 """Check for sensible looking, totally invalid OS macros."""
4168 preprocessor_statement = input_api.re.compile(r'^\s*#')
4169 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4170 results = []
4171 for lnum, line in f.ChangedContents():
4172 if preprocessor_statement.search(line):
4173 for match in os_macro.finditer(line):
4174 if not match.group(1) in _VALID_OS_MACROS:
4175 good = _DidYouMeanOSMacro(match.group(1))
4176 did_you_mean = ' (did you mean %s?)' % good if good else ''
4177 results.append(' %s:%d %s%s' % (f.LocalPath(),
4178 lnum,
4179 match.group(1),
4180 did_you_mean))
4181 return results
4182
4183
4184def _CheckForInvalidOSMacros(input_api, output_api):
4185 """Check all affected files for invalid OS macros."""
4186 bad_macros = []
tzik3f295992018-12-04 20:32:234187 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474188 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544189 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4190
4191 if not bad_macros:
4192 return []
4193
4194 return [output_api.PresubmitError(
4195 'Possibly invalid OS macro[s] found. Please fix your code\n'
4196 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4197
lliabraa35bab3932014-10-01 12:16:444198
4199def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4200 """Check all affected files for invalid "if defined" macros."""
4201 ALWAYS_DEFINED_MACROS = (
4202 "TARGET_CPU_PPC",
4203 "TARGET_CPU_PPC64",
4204 "TARGET_CPU_68K",
4205 "TARGET_CPU_X86",
4206 "TARGET_CPU_ARM",
4207 "TARGET_CPU_MIPS",
4208 "TARGET_CPU_SPARC",
4209 "TARGET_CPU_ALPHA",
4210 "TARGET_IPHONE_SIMULATOR",
4211 "TARGET_OS_EMBEDDED",
4212 "TARGET_OS_IPHONE",
4213 "TARGET_OS_MAC",
4214 "TARGET_OS_UNIX",
4215 "TARGET_OS_WIN32",
4216 )
4217 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4218 results = []
4219 for lnum, line in f.ChangedContents():
4220 for match in ifdef_macro.finditer(line):
4221 if match.group(1) in ALWAYS_DEFINED_MACROS:
4222 always_defined = ' %s is always defined. ' % match.group(1)
4223 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4224 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4225 lnum,
4226 always_defined,
4227 did_you_mean))
4228 return results
4229
4230
4231def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4232 """Check all affected files for invalid "if defined" macros."""
4233 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054234 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444235 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054236 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214237 continue
lliabraa35bab3932014-10-01 12:16:444238 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4239 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4240
4241 if not bad_macros:
4242 return []
4243
4244 return [output_api.PresubmitError(
4245 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4246 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4247 bad_macros)]
4248
4249
mlamouria82272622014-09-16 18:45:044250def _CheckForIPCRules(input_api, output_api):
4251 """Check for same IPC rules described in
4252 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4253 """
4254 base_pattern = r'IPC_ENUM_TRAITS\('
4255 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4256 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4257
4258 problems = []
4259 for f in input_api.AffectedSourceFiles(None):
4260 local_path = f.LocalPath()
4261 if not local_path.endswith('.h'):
4262 continue
4263 for line_number, line in f.ChangedContents():
4264 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4265 problems.append(
4266 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4267
4268 if problems:
4269 return [output_api.PresubmitPromptWarning(
4270 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4271 else:
4272 return []
4273
[email protected]b00342e7f2013-03-26 16:21:544274
Stephen Martinis97a394142018-06-07 23:06:054275def _CheckForLongPathnames(input_api, output_api):
4276 """Check to make sure no files being submitted have long paths.
4277 This causes issues on Windows.
4278 """
4279 problems = []
4280 for f in input_api.AffectedSourceFiles(None):
4281 local_path = f.LocalPath()
4282 # Windows has a path limit of 260 characters. Limit path length to 200 so
4283 # that we have some extra for the prefix on dev machines and the bots.
4284 if len(local_path) > 200:
4285 problems.append(local_path)
4286
4287 if problems:
4288 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4289 else:
4290 return []
4291
4292
Daniel Bratell8ba52722018-03-02 16:06:144293def _CheckForIncludeGuards(input_api, output_api):
4294 """Check that header files have proper guards against multiple inclusion.
4295 If a file should not have such guards (and it probably should) then it
4296 should include the string "no-include-guard-because-multiply-included".
4297 """
Daniel Bratell6a75baef62018-06-04 10:04:454298 def is_chromium_header_file(f):
4299 # We only check header files under the control of the Chromium
4300 # project. That is, those outside third_party apart from
4301 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324302 # We also exclude *_message_generator.h headers as they use
4303 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454304 file_with_path = input_api.os_path.normpath(f.LocalPath())
4305 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324306 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454307 (not file_with_path.startswith('third_party') or
4308 file_with_path.startswith(
4309 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144310
4311 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344312 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144313
4314 errors = []
4315
Daniel Bratell6a75baef62018-06-04 10:04:454316 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144317 guard_name = None
4318 guard_line_number = None
4319 seen_guard_end = False
4320
4321 file_with_path = input_api.os_path.normpath(f.LocalPath())
4322 base_file_name = input_api.os_path.splitext(
4323 input_api.os_path.basename(file_with_path))[0]
4324 upper_base_file_name = base_file_name.upper()
4325
4326 expected_guard = replace_special_with_underscore(
4327 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144328
4329 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574330 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4331 # are too many (1000+) files with slight deviations from the
4332 # coding style. The most important part is that the include guard
4333 # is there, and that it's unique, not the name so this check is
4334 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144335 #
4336 # As code becomes more uniform, this could be made stricter.
4337
4338 guard_name_pattern_list = [
4339 # Anything with the right suffix (maybe with an extra _).
4340 r'\w+_H__?',
4341
Daniel Bratell39b5b062018-05-16 18:09:574342 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144343 r'\w+_h',
4344
4345 # Anything including the uppercase name of the file.
4346 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4347 upper_base_file_name)) + r'\w*',
4348 ]
4349 guard_name_pattern = '|'.join(guard_name_pattern_list)
4350 guard_pattern = input_api.re.compile(
4351 r'#ifndef\s+(' + guard_name_pattern + ')')
4352
4353 for line_number, line in enumerate(f.NewContents()):
4354 if 'no-include-guard-because-multiply-included' in line:
4355 guard_name = 'DUMMY' # To not trigger check outside the loop.
4356 break
4357
4358 if guard_name is None:
4359 match = guard_pattern.match(line)
4360 if match:
4361 guard_name = match.group(1)
4362 guard_line_number = line_number
4363
Daniel Bratell39b5b062018-05-16 18:09:574364 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454365 # don't match the chromium style guide, but new files should
4366 # get it right.
4367 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574368 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144369 errors.append(output_api.PresubmitPromptWarning(
4370 'Header using the wrong include guard name %s' % guard_name,
4371 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574372 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144373 else:
4374 # The line after #ifndef should have a #define of the same name.
4375 if line_number == guard_line_number + 1:
4376 expected_line = '#define %s' % guard_name
4377 if line != expected_line:
4378 errors.append(output_api.PresubmitPromptWarning(
4379 'Missing "%s" for include guard' % expected_line,
4380 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4381 'Expected: %r\nGot: %r' % (expected_line, line)))
4382
4383 if not seen_guard_end and line == '#endif // %s' % guard_name:
4384 seen_guard_end = True
4385 elif seen_guard_end:
4386 if line.strip() != '':
4387 errors.append(output_api.PresubmitPromptWarning(
4388 'Include guard %s not covering the whole file' % (
4389 guard_name), [f.LocalPath()]))
4390 break # Nothing else to check and enough to warn once.
4391
4392 if guard_name is None:
4393 errors.append(output_api.PresubmitPromptWarning(
4394 'Missing include guard %s' % expected_guard,
4395 [f.LocalPath()],
4396 'Missing include guard in %s\n'
4397 'Recommended name: %s\n'
4398 'This check can be disabled by having the string\n'
4399 'no-include-guard-because-multiply-included in the header.' %
4400 (f.LocalPath(), expected_guard)))
4401
4402 return errors
4403
4404
mostynbb639aca52015-01-07 20:31:234405def _CheckForWindowsLineEndings(input_api, output_api):
4406 """Check source code and known ascii text files for Windows style line
4407 endings.
4408 """
earthdok1b5e0ee2015-03-10 15:19:104409 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234410
4411 file_inclusion_pattern = (
4412 known_text_files,
4413 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4414 )
4415
mostynbb639aca52015-01-07 20:31:234416 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534417 source_file_filter = lambda f: input_api.FilterSourceFile(
4418 f, white_list=file_inclusion_pattern, black_list=None)
4419 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504420 include_file = False
4421 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234422 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504423 include_file = True
4424 if include_file:
4425 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234426
4427 if problems:
4428 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4429 'these files to contain Windows style line endings?\n' +
4430 '\n'.join(problems))]
4431
4432 return []
4433
4434
Vaclav Brozekd5de76a2018-03-17 07:57:504435def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134436 """Checks that all source files use SYSLOG properly."""
4437 syslog_files = []
4438 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564439 for line_number, line in f.ChangedContents():
4440 if 'SYSLOG' in line:
4441 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4442
pastarmovj89f7ee12016-09-20 14:58:134443 if syslog_files:
4444 return [output_api.PresubmitPromptWarning(
4445 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4446 ' calls.\nFiles to check:\n', items=syslog_files)]
4447 return []
4448
4449
[email protected]1f7b4172010-01-28 01:17:344450def CheckChangeOnUpload(input_api, output_api):
4451 results = []
4452 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474453 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284454 results.extend(
jam93a6ee792017-02-08 23:59:224455 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194456 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224457 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134458 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164459 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534460 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194461 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274462 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544463 return results
[email protected]ca8d1982009-02-19 16:33:124464
4465
[email protected]1bfb8322014-04-23 01:02:414466def GetTryServerMasterForBot(bot):
4467 """Returns the Try Server master for the given bot.
4468
[email protected]0bb112362014-07-26 04:38:324469 It tries to guess the master from the bot name, but may still fail
4470 and return None. There is no longer a default master.
4471 """
4472 # Potentially ambiguous bot names are listed explicitly.
4473 master_map = {
tandriie5587792016-07-14 00:34:504474 'chromium_presubmit': 'master.tryserver.chromium.linux',
4475 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414476 }
[email protected]0bb112362014-07-26 04:38:324477 master = master_map.get(bot)
4478 if not master:
wnwen4fbaab82016-05-25 12:54:364479 if 'android' in bot:
tandriie5587792016-07-14 00:34:504480 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364481 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504482 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324483 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504484 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324485 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504486 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324487 return master
[email protected]1bfb8322014-04-23 01:02:414488
4489
[email protected]ca8d1982009-02-19 16:33:124490def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544491 results = []
[email protected]1f7b4172010-01-28 01:17:344492 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574493 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544494 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274495 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344496 input_api,
4497 output_api,
[email protected]2fdd1f362013-01-16 03:56:034498 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274499
jam93a6ee792017-02-08 23:59:224500 results.extend(
4501 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544502 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4503 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384504 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4505 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414506 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4507 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544508 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144509
4510
4511def _CheckTranslationScreenshots(input_api, output_api):
4512 PART_FILE_TAG = "part"
4513 import os
4514 import sys
4515 from io import StringIO
4516
4517 try:
4518 old_sys_path = sys.path
4519 sys.path = sys.path + [input_api.os_path.join(
4520 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4521 import grit.grd_reader
4522 import grit.node.message
4523 import grit.util
4524 finally:
4525 sys.path = old_sys_path
4526
4527 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4528 """Load the grd file and return a dict of message ids to messages.
4529
4530 Ignores any nested grdp files pointed by <part> tag.
4531 """
4532 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4533 stop_after=None, first_ids_file=None,
Julian Pastarmov4f7af532019-07-17 19:25:374534 debug=False, defines={'_chromium': 1},
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144535 tags_to_ignore=set([PART_FILE_TAG]))
4536 return {
4537 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4538 grit.node.message.MessageNode)
4539 }
4540
4541 def _GetGrdpMessagesFromString(grdp_string):
4542 """Parses the contents of a grdp file given in grdp_string.
4543
4544 grd_reader can't parse grdp files directly. Instead, this creates a
4545 temporary directory with a grd file pointing to the grdp file, and loads the
4546 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4547 """
4548 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4549 <grit latest_public_release="1" current_release="1">
4550 <release seq="1">
4551 <messages>
4552 <part file="sub.grdp" />
4553 </messages>
4554 </release>
4555 </grit>
4556 """
4557 with grit.util.TempDir({'main.grd': WRAPPER,
4558 'sub.grdp': grdp_string}) as temp_dir:
4559 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4560
4561 new_or_added_paths = set(f.LocalPath()
4562 for f in input_api.AffectedFiles()
4563 if (f.Action() == 'A' or f.Action() == 'M'))
4564 removed_paths = set(f.LocalPath()
4565 for f in input_api.AffectedFiles(include_deletes=True)
4566 if f.Action() == 'D')
4567
4568 affected_grds = [f for f in input_api.AffectedFiles()
4569 if (f.LocalPath().endswith('.grd') or
4570 f.LocalPath().endswith('.grdp'))]
4571 affected_png_paths = [f.AbsoluteLocalPath()
4572 for f in input_api.AffectedFiles()
4573 if (f.LocalPath().endswith('.png'))]
4574
4575 # Check for screenshots. Developers can upload screenshots using
4576 # tools/translation/upload_screenshots.py which finds and uploads
4577 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4578 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4579 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4580 #
4581 # The logic here is as follows:
4582 #
4583 # - If the CL has a .png file under the screenshots directory for a grd
4584 # file, warn the developer. Actual images should never be checked into the
4585 # Chrome repo.
4586 #
4587 # - If the CL contains modified or new messages in grd files and doesn't
4588 # contain the corresponding .sha1 files, warn the developer to add images
4589 # and upload them via tools/translation/upload_screenshots.py.
4590 #
4591 # - If the CL contains modified or new messages in grd files and the
4592 # corresponding .sha1 files, everything looks good.
4593 #
4594 # - If the CL contains removed messages in grd files but the corresponding
4595 # .sha1 files aren't removed, warn the developer to remove them.
4596 unnecessary_screenshots = []
4597 missing_sha1 = []
4598 unnecessary_sha1_files = []
4599
4600
4601 def _CheckScreenshotAdded(screenshots_dir, message_id):
4602 sha1_path = input_api.os_path.join(
4603 screenshots_dir, message_id + '.png.sha1')
4604 if sha1_path not in new_or_added_paths:
4605 missing_sha1.append(sha1_path)
4606
4607
4608 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4609 sha1_path = input_api.os_path.join(
4610 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034611 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144612 unnecessary_sha1_files.append(sha1_path)
4613
4614
4615 for f in affected_grds:
4616 file_path = f.LocalPath()
4617 old_id_to_msg_map = {}
4618 new_id_to_msg_map = {}
4619 if file_path.endswith('.grdp'):
4620 if f.OldContents():
4621 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394622 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144623 if f.NewContents():
4624 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394625 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144626 else:
4627 if f.OldContents():
4628 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394629 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144630 if f.NewContents():
4631 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394632 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144633
4634 # Compute added, removed and modified message IDs.
4635 old_ids = set(old_id_to_msg_map)
4636 new_ids = set(new_id_to_msg_map)
4637 added_ids = new_ids - old_ids
4638 removed_ids = old_ids - new_ids
4639 modified_ids = set([])
4640 for key in old_ids.intersection(new_ids):
4641 if (old_id_to_msg_map[key].FormatXml()
4642 != new_id_to_msg_map[key].FormatXml()):
4643 modified_ids.add(key)
4644
4645 grd_name, ext = input_api.os_path.splitext(
4646 input_api.os_path.basename(file_path))
4647 screenshots_dir = input_api.os_path.join(
4648 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4649
4650 # Check the screenshot directory for .png files. Warn if there is any.
4651 for png_path in affected_png_paths:
4652 if png_path.startswith(screenshots_dir):
4653 unnecessary_screenshots.append(png_path)
4654
4655 for added_id in added_ids:
4656 _CheckScreenshotAdded(screenshots_dir, added_id)
4657
4658 for modified_id in modified_ids:
4659 _CheckScreenshotAdded(screenshots_dir, modified_id)
4660
4661 for removed_id in removed_ids:
4662 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4663
4664 results = []
4665 if unnecessary_screenshots:
4666 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394667 'Do not include actual screenshots in the changelist. Run '
4668 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144669 sorted(unnecessary_screenshots)))
4670
4671 if missing_sha1:
4672 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394673 'You are adding or modifying UI strings.\n'
4674 'To ensure the best translations, take screenshots of the relevant UI '
4675 '(https://g.co/chrome/translation) and add these files to your '
4676 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144677
4678 if unnecessary_sha1_files:
4679 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394680 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144681 sorted(unnecessary_sha1_files)))
4682
4683 return results