blob: a8b1139af9555be10e98a677c62f41df4f899bae [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
28 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
29 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1430 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5432 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4034)
[email protected]ca8d1982009-02-19 16:33:1235
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Fragment of a regular expression that matches C++ and Objective-C++
38# implementation files.
39_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40
wnwenbdc444e2016-05-25 13:44:1541
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1942# Fragment of a regular expression that matches C++ and Objective-C++
43# header files.
44_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
45
46
[email protected]06e6d0ff2012-12-11 01:36:4447# Regular expression that matches code only used for test binaries
48# (best effort).
49_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0450 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4452 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1253 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1854 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4455 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0456 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0557 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0458 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4759 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0460 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0861 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0462 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4463)
[email protected]ca8d1982009-02-19 16:33:1264
Daniel Bratell609102be2019-03-27 20:53:2165_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1566
[email protected]eea609a2011-11-18 13:10:1267_TEST_ONLY_WARNING = (
68 'You might be calling functions intended only for testing from\n'
69 'production code. It is OK to ignore this warning if you know what\n'
70 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5871 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1272
73
[email protected]cf9b78f2012-11-14 11:40:2874_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4075 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2176 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
77 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2878
wnwenbdc444e2016-05-25 13:44:1579
Daniel Bratell609102be2019-03-27 20:53:2180# Format: Sequence of tuples containing:
81# * String pattern or, if starting with a slash, a regular expression.
82# * Sequence of strings to show when the pattern matches.
83# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4184_BANNED_JAVA_FUNCTIONS = (
85 (
86 'StrictMode.allowThreadDiskReads()',
87 (
88 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
89 'directly.',
90 ),
91 False,
92 ),
93 (
94 'StrictMode.allowThreadDiskWrites()',
95 (
96 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
97 'directly.',
98 ),
99 False,
100 ),
101)
102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59107_BANNED_OBJC_FUNCTIONS = (
108 (
109 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20110 (
111 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59112 'prohibited. Please use CrTrackingArea instead.',
113 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
114 ),
115 False,
116 ),
117 (
[email protected]eaae1972014-04-16 04:17:26118 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20119 (
120 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59121 'instead.',
122 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
123 ),
124 False,
125 ),
126 (
127 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20128 (
129 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59130 'Please use |convertPoint:(point) fromView:nil| instead.',
131 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
132 ),
133 True,
134 ),
135 (
136 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20137 (
138 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59139 'Please use |convertPoint:(point) toView:nil| instead.',
140 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 ),
142 True,
143 ),
144 (
145 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20146 (
147 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59148 'Please use |convertRect:(point) fromView:nil| instead.',
149 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
150 ),
151 True,
152 ),
153 (
154 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59157 'Please use |convertRect:(point) toView:nil| instead.',
158 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
159 ),
160 True,
161 ),
162 (
163 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20164 (
165 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59166 'Please use |convertSize:(point) fromView:nil| instead.',
167 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
168 ),
169 True,
170 ),
171 (
172 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20173 (
174 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59175 'Please use |convertSize:(point) toView:nil| instead.',
176 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
177 ),
178 True,
179 ),
jif65398702016-10-27 10:19:48180 (
181 r"/\s+UTF8String\s*]",
182 (
183 'The use of -[NSString UTF8String] is dangerous as it can return null',
184 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
185 'Please use |SysNSStringToUTF8| instead.',
186 ),
187 True,
188 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34189 (
190 r'__unsafe_unretained',
191 (
192 'The use of __unsafe_unretained is almost certainly wrong, unless',
193 'when interacting with NSFastEnumeration or NSInvocation.',
194 'Please use __weak in files build with ARC, nothing otherwise.',
195 ),
196 False,
197 ),
Avi Drissman7382afa02019-04-29 23:27:13198 (
199 'freeWhenDone:NO',
200 (
201 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
202 'Foundation types is prohibited.',
203 ),
204 True,
205 ),
[email protected]127f18ec2012-06-16 05:05:59206)
207
Daniel Bratell609102be2019-03-27 20:53:21208# Format: Sequence of tuples containing:
209# * String pattern or, if starting with a slash, a regular expression.
210# * Sequence of strings to show when the pattern matches.
211# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54212_BANNED_IOS_OBJC_FUNCTIONS = (
213 (
214 r'/\bTEST[(]',
215 (
216 'TEST() macro should not be used in Objective-C++ code as it does not ',
217 'drain the autorelease pool at the end of the test. Use TEST_F() ',
218 'macro instead with a fixture inheriting from PlatformTest (or a ',
219 'typedef).'
220 ),
221 True,
222 ),
223 (
224 r'/\btesting::Test\b',
225 (
226 'testing::Test should not be used in Objective-C++ code as it does ',
227 'not drain the autorelease pool at the end of the test. Use ',
228 'PlatformTest instead.'
229 ),
230 True,
231 ),
232)
233
Peter K. Lee6c03ccff2019-07-15 14:40:05234# Format: Sequence of tuples containing:
235# * String pattern or, if starting with a slash, a regular expression.
236# * Sequence of strings to show when the pattern matches.
237# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
238_BANNED_IOS_EGTEST_FUNCTIONS = (
239 (
240 r'/\bEXPECT_OCMOCK_VERIFY\b',
241 (
242 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
243 'it is meant for GTests. Use [mock verify] instead.'
244 ),
245 True,
246 ),
247)
248
danakj7a2b7082019-05-21 21:13:51249# Directories that contain deprecated Bind() or Callback types.
250# Find sub-directories from a given directory by running:
251# for i in `find . -maxdepth 1 -type d`; do
252# echo "-- $i"
253# (cd $i; git grep -P 'base::(Bind\(|(Callback<|Closure))'|wc -l)
254# done
255#
256# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
257# when they have been converted to modern callback types (OnceCallback,
258# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
259# checks for them and prevent regressions.
260_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
261 '^android_webview/browser/',
262 '^apps/',
263 '^ash/',
danakj7a2b7082019-05-21 21:13:51264 '^base/callback.h', # Intentional.
265 '^chrome/app/',
266 '^chrome/browser/',
267 '^chrome/chrome_elf/',
268 '^chrome/chrome_watcher/',
269 '^chrome/common/',
270 '^chrome/installer/',
271 '^chrome/notification_helper/',
272 '^chrome/renderer/',
273 '^chrome/services/',
274 '^chrome/test/',
275 '^chrome/tools/',
276 '^chrome/utility/',
277 '^chromecast/app/',
278 '^chromecast/browser/',
279 '^chromecast/crash/',
280 '^chromecast/media/',
281 '^chromecast/metrics/',
282 '^chromecast/net/',
283 '^chromeos/attestation/',
284 '^chromeos/audio/',
285 '^chromeos/components/',
286 '^chromeos/cryptohome/',
287 '^chromeos/dbus/',
288 '^chromeos/geolocation/',
289 '^chromeos/login/',
290 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51291 '^chromeos/process_proxy/',
292 '^chromeos/services/',
293 '^chromeos/settings/',
294 '^chromeos/timezone/',
295 '^chromeos/tpm/',
296 '^components/arc/',
297 '^components/assist_ranker/',
298 '^components/autofill/',
299 '^components/autofill_assistant/',
300 '^components/bookmarks/',
301 '^components/browser_sync/',
302 '^components/browser_watcher/',
303 '^components/browsing_data/',
304 '^components/cast_channel/',
305 '^components/certificate_transparency/',
306 '^components/chromeos_camera/',
307 '^components/component_updater/',
308 '^components/content_settings/',
309 '^components/crash/',
310 '^components/cronet/',
311 '^components/data_reduction_proxy/',
312 '^components/discardable_memory/',
313 '^components/dom_distiller/',
314 '^components/domain_reliability/',
315 '^components/download/',
316 '^components/drive/',
317 '^components/exo/',
318 '^components/favicon/',
319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
323 '^components/google/',
324 '^components/guest_view/',
325 '^components/heap_profiling/',
326 '^components/history/',
327 '^components/image_fetcher/',
328 '^components/invalidation/',
329 '^components/keyed_service/',
330 '^components/login/',
331 '^components/metrics/',
332 '^components/metrics_services_manager/',
333 '^components/nacl/',
334 '^components/navigation_interception/',
335 '^components/net_log/',
336 '^components/network_time/',
337 '^components/ntp_snippets/',
338 '^components/ntp_tiles/',
339 '^components/offline_items_collection/',
340 '^components/offline_pages/',
341 '^components/omnibox/',
342 '^components/ownership/',
343 '^components/pairing/',
344 '^components/password_manager/',
345 '^components/payments/',
346 '^components/plugins/',
347 '^components/policy/',
348 '^components/pref_registry/',
349 '^components/prefs/',
danakj7a2b7082019-05-21 21:13:51350 '^components/proxy_config/',
351 '^components/quirks/',
352 '^components/rappor/',
353 '^components/remote_cocoa/',
354 '^components/renderer_context_menu/',
355 '^components/rlz/',
356 '^components/safe_browsing/',
357 '^components/search_engines/',
358 '^components/search_provider_logos/',
359 '^components/security_interstitials/',
360 '^components/security_state/',
361 '^components/services/',
362 '^components/sessions/',
363 '^components/signin/',
364 '^components/ssl_errors/',
365 '^components/storage_monitor/',
366 '^components/subresource_filter/',
367 '^components/suggestions/',
368 '^components/supervised_user_error_page/',
369 '^components/sync/',
370 '^components/sync_bookmarks/',
371 '^components/sync_device_info/',
372 '^components/sync_preferences/',
373 '^components/sync_sessions/',
374 '^components/test/',
375 '^components/tracing/',
376 '^components/translate/',
377 '^components/ukm/',
378 '^components/update_client/',
379 '^components/upload_list/',
380 '^components/variations/',
381 '^components/visitedlink/',
382 '^components/web_cache/',
383 '^components/web_resource/',
danakj7a2b7082019-05-21 21:13:51384 '^components/webcrypto/',
385 '^components/webdata/',
386 '^components/webdata_services/',
387 '^components/wifi/',
388 '^components/zoom/',
389 '^content/app/',
390 '^content/browser/',
391 '^content/child/',
392 '^content/common/',
393 '^content/public/',
394 '^content/renderer/android/',
395 '^content/renderer/fetchers/',
396 '^content/renderer/image_downloader/',
397 '^content/renderer/input/',
398 '^content/renderer/java/',
399 '^content/renderer/media/',
400 '^content/renderer/media_capture_from_element/',
401 '^content/renderer/media_recorder/',
402 '^content/renderer/p2p/',
403 '^content/renderer/pepper/',
404 '^content/renderer/service_worker/',
405 '^content/renderer/worker/',
406 '^content/test/',
407 '^content/utility/',
408 '^dbus/',
409 '^device/base/',
410 '^device/bluetooth/',
411 '^device/fido/',
412 '^device/gamepad/',
413 '^device/udev_linux/',
414 '^device/vr/',
415 '^extensions/',
416 '^gin/',
417 '^google_apis/dive/',
418 '^google_apis/gaia/',
419 '^google_apis/gcm/',
420 '^headless/',
421 '^ios/chrome/',
422 '^ios/components/',
423 '^ios/net/',
424 '^ios/web/',
425 '^ios/web_view/',
426 '^ipc/',
427 '^media/audio/',
428 '^media/base/',
429 '^media/capture/',
430 '^media/cast/',
431 '^media/cdm/',
432 '^media/device_monitors/',
433 '^media/ffmpeg/',
434 '^media/filters/',
435 '^media/formats/',
436 '^media/gpu/',
437 '^media/mojo/',
438 '^media/muxers/',
439 '^media/remoting/',
440 '^media/renderers/',
441 '^media/test/',
442 '^mojo/core/',
443 '^mojo/public/',
444 '^net/',
445 '^ppapi/proxy/',
446 '^ppapi/shared_impl/',
447 '^ppapi/tests/',
448 '^ppapi/thunk/',
449 '^remoting/base/',
450 '^remoting/client/',
451 '^remoting/codec/',
452 '^remoting/host/',
453 '^remoting/internal/',
454 '^remoting/ios/',
455 '^remoting/protocol/',
456 '^remoting/signaling/',
457 '^remoting/test/',
458 '^sandbox/linux/',
459 '^sandbox/win/',
460 '^services/',
461 '^storage/browser/',
462 '^testing/gmock_mutant.h',
463 '^testing/libfuzzer/',
464 '^third_party/blink/',
465 '^third_party/crashpad/crashpad/test/gtest_main.cc',
466 '^third_party/leveldatabase/leveldb_chrome.cc',
467 '^third_party/boringssl/gtest_main_chromium.cc',
468 '^third_party/cacheinvalidation/overrides/' +
469 'google/cacheinvalidation/deps/callback.h',
470 '^third_party/libaddressinput/chromium/chrome_address_validator.cc',
471 '^third_party/zlib/google/',
472 '^tools/android/',
473 '^tools/clang/base_bind_rewriters/', # Intentional.
474 '^tools/gdb/gdb_chrome.py', # Intentional.
475 '^ui/accelerated_widget_mac/',
476 '^ui/android/',
477 '^ui/aura/',
478 '^ui/base/',
479 '^ui/compositor/',
480 '^ui/display/',
481 '^ui/events/',
482 '^ui/gfx/',
483 '^ui/message_center/',
danakj7a2b7082019-05-21 21:13:51484 '^ui/snapshot/',
485 '^ui/views_content_client/',
486 '^ui/wm/',
487))
[email protected]127f18ec2012-06-16 05:05:59488
Daniel Bratell609102be2019-03-27 20:53:21489# Format: Sequence of tuples containing:
490# * String pattern or, if starting with a slash, a regular expression.
491# * Sequence of strings to show when the pattern matches.
492# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
493# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59494_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20495 (
Dave Tapuska98199b612019-07-10 13:30:44496 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53497 (
498 'New code should not use NULL. Use nullptr instead.',
499 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20500 False,
thomasandersone7caaa9b2017-03-29 19:22:53501 (),
502 ),
Antonio Gomes07300d02019-03-13 20:59:57503 # Make sure that gtest's FRIEND_TEST() macro is not used; the
504 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
505 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53506 (
[email protected]23e6cbc2012-06-16 18:51:20507 'FRIEND_TEST(',
508 (
[email protected]e3c945502012-06-26 20:01:49509 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20510 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
511 ),
512 False,
[email protected]7345da02012-11-27 14:31:49513 (),
[email protected]23e6cbc2012-06-16 18:51:20514 ),
515 (
Dave Tapuska98199b612019-07-10 13:30:44516 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53517 (
518 'Chrome clients wishing to select events on X windows should use',
519 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
520 'you are selecting events from the GPU process, or if you are using',
521 'an XDisplay other than gfx::GetXDisplay().',
522 ),
523 True,
524 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40525 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04526 r"^ui[\\/]gl[\\/].*\.cc$",
527 r"^media[\\/]gpu[\\/].*\.cc$",
528 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53529 ),
530 ),
531 (
Dave Tapuska98199b612019-07-10 13:30:44532 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20533 (
thomasanderson11aa41d2017-06-08 22:22:38534 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20535 ),
536 True,
537 (
Egor Paskoce145c42018-09-28 19:31:04538 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
539 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
540 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20541 ),
542 ),
543 (
tomhudsone2c14d552016-05-26 17:07:46544 'setMatrixClip',
545 (
546 'Overriding setMatrixClip() is prohibited; ',
547 'the base function is deprecated. ',
548 ),
549 True,
550 (),
551 ),
552 (
[email protected]52657f62013-05-20 05:30:31553 'SkRefPtr',
554 (
555 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22556 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31557 ),
558 True,
559 (),
560 ),
561 (
562 'SkAutoRef',
563 (
564 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22565 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31566 ),
567 True,
568 (),
569 ),
570 (
571 'SkAutoTUnref',
572 (
573 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22574 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31575 ),
576 True,
577 (),
578 ),
579 (
580 'SkAutoUnref',
581 (
582 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
583 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22584 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31585 ),
586 True,
587 (),
588 ),
[email protected]d89eec82013-12-03 14:10:59589 (
590 r'/HANDLE_EINTR\(.*close',
591 (
592 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
593 'descriptor will be closed, and it is incorrect to retry the close.',
594 'Either call close directly and ignore its return value, or wrap close',
595 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
596 ),
597 True,
598 (),
599 ),
600 (
601 r'/IGNORE_EINTR\((?!.*close)',
602 (
603 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
604 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
605 ),
606 True,
607 (
608 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04609 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
610 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59611 ),
612 ),
[email protected]ec5b3f02014-04-04 18:43:43613 (
614 r'/v8::Extension\(',
615 (
616 'Do not introduce new v8::Extensions into the code base, use',
617 'gin::Wrappable instead. See http://crbug.com/334679',
618 ),
619 True,
[email protected]f55c90ee62014-04-12 00:50:03620 (
Egor Paskoce145c42018-09-28 19:31:04621 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03622 ),
[email protected]ec5b3f02014-04-04 18:43:43623 ),
skyostilf9469f72015-04-20 10:38:52624 (
jame2d1a952016-04-02 00:27:10625 '#pragma comment(lib,',
626 (
627 'Specify libraries to link with in build files and not in the source.',
628 ),
629 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41630 (
tzik3f295992018-12-04 20:32:23631 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04632 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41633 ),
jame2d1a952016-04-02 00:27:10634 ),
fdorayc4ac18d2017-05-01 21:39:59635 (
Gabriel Charette7cc6c432018-04-25 20:52:02636 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59637 (
638 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
639 ),
640 False,
641 (),
642 ),
643 (
Gabriel Charette7cc6c432018-04-25 20:52:02644 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59645 (
646 'Consider using THREAD_CHECKER macros instead of the class directly.',
647 ),
648 False,
649 (),
650 ),
dbeamb6f4fde2017-06-15 04:03:06651 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06652 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
653 (
654 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
655 'deprecated (http://crbug.com/634507). Please avoid converting away',
656 'from the Time types in Chromium code, especially if any math is',
657 'being done on time values. For interfacing with platform/library',
658 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
659 'type converter methods instead. For faking TimeXXX values (for unit',
660 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
661 'other use cases, please contact base/time/OWNERS.',
662 ),
663 False,
664 (),
665 ),
666 (
dbeamb6f4fde2017-06-15 04:03:06667 'CallJavascriptFunctionUnsafe',
668 (
669 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
670 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
671 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
672 ),
673 False,
674 (
Egor Paskoce145c42018-09-28 19:31:04675 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
676 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
677 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06678 ),
679 ),
dskiba1474c2bfd62017-07-20 02:19:24680 (
681 'leveldb::DB::Open',
682 (
683 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
684 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
685 "Chrome's tracing, making their memory usage visible.",
686 ),
687 True,
688 (
689 r'^third_party/leveldatabase/.*\.(cc|h)$',
690 ),
Gabriel Charette0592c3a2017-07-26 12:02:04691 ),
692 (
Chris Mumfordc38afb62017-10-09 17:55:08693 'leveldb::NewMemEnv',
694 (
695 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58696 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
697 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08698 ),
699 True,
700 (
701 r'^third_party/leveldatabase/.*\.(cc|h)$',
702 ),
703 ),
704 (
Gabriel Charetted9839bc2017-07-29 14:17:47705 'RunLoop::QuitCurrent',
706 (
Robert Liao64b7ab22017-08-04 23:03:43707 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
708 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47709 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41710 False,
Gabriel Charetted9839bc2017-07-29 14:17:47711 (),
Gabriel Charettea44975052017-08-21 23:14:04712 ),
713 (
714 'base::ScopedMockTimeMessageLoopTaskRunner',
715 (
Gabriel Charette87cc1af2018-04-25 20:52:51716 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11717 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51718 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
719 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
720 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04721 ),
Gabriel Charette87cc1af2018-04-25 20:52:51722 False,
Gabriel Charettea44975052017-08-21 23:14:04723 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57724 ),
725 (
Dave Tapuska98199b612019-07-10 13:30:44726 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57727 (
728 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02729 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57730 ),
731 True,
732 (),
Francois Doray43670e32017-09-27 12:40:38733 ),
734 (
Peter Kasting991618a62019-06-17 22:00:09735 r'/\bstd::stoi\b',
736 (
737 'std::stoi uses exceptions to communicate results. ',
738 'Use base::StringToInt() instead.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
742 ),
743 (
744 r'/\bstd::stol\b',
745 (
746 'std::stol uses exceptions to communicate results. ',
747 'Use base::StringToInt() instead.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
751 ),
752 (
753 r'/\bstd::stoul\b',
754 (
755 'std::stoul uses exceptions to communicate results. ',
756 'Use base::StringToUint() instead.',
757 ),
758 True,
759 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
760 ),
761 (
762 r'/\bstd::stoll\b',
763 (
764 'std::stoll uses exceptions to communicate results. ',
765 'Use base::StringToInt64() instead.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
769 ),
770 (
771 r'/\bstd::stoull\b',
772 (
773 'std::stoull uses exceptions to communicate results. ',
774 'Use base::StringToUint64() instead.',
775 ),
776 True,
777 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
778 ),
779 (
780 r'/\bstd::stof\b',
781 (
782 'std::stof uses exceptions to communicate results. ',
783 'For locale-independent values, e.g. reading numbers from disk',
784 'profiles, use base::StringToDouble().',
785 'For user-visible values, parse using ICU.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
789 ),
790 (
791 r'/\bstd::stod\b',
792 (
793 'std::stod uses exceptions to communicate results. ',
794 'For locale-independent values, e.g. reading numbers from disk',
795 'profiles, use base::StringToDouble().',
796 'For user-visible values, parse using ICU.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
800 ),
801 (
802 r'/\bstd::stold\b',
803 (
804 'std::stold uses exceptions to communicate results. ',
805 'For locale-independent values, e.g. reading numbers from disk',
806 'profiles, use base::StringToDouble().',
807 'For user-visible values, parse using ICU.',
808 ),
809 True,
810 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
811 ),
812 (
Daniel Bratell69334cc2019-03-26 11:07:45813 r'/\bstd::to_string\b',
814 (
815 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09816 'For locale-independent strings, e.g. writing numbers to disk',
817 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45818 'For user-visible strings, use base::FormatNumber() and',
819 'the related functions in base/i18n/number_formatting.h.',
820 ),
Peter Kasting991618a62019-06-17 22:00:09821 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21822 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45823 ),
824 (
825 r'/\bstd::shared_ptr\b',
826 (
827 'std::shared_ptr should not be used. Use scoped_refptr instead.',
828 ),
829 True,
Daniel Bratell609102be2019-03-27 20:53:21830 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
831 ),
832 (
Peter Kasting991618a62019-06-17 22:00:09833 r'/\bstd::weak_ptr\b',
834 (
835 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
836 ),
837 True,
838 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
839 ),
840 (
Daniel Bratell609102be2019-03-27 20:53:21841 r'/\blong long\b',
842 (
843 'long long is banned. Use stdint.h if you need a 64 bit number.',
844 ),
845 False, # Only a warning since it is already used.
846 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
847 ),
848 (
849 r'/\bstd::bind\b',
850 (
851 'std::bind is banned because of lifetime risks.',
852 'Use base::BindOnce or base::BindRepeating instead.',
853 ),
854 True,
855 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
856 ),
857 (
858 r'/\b#include <chrono>\b',
859 (
860 '<chrono> overlaps with Time APIs in base. Keep using',
861 'base classes.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
865 ),
866 (
867 r'/\b#include <exception>\b',
868 (
869 'Exceptions are banned and disabled in Chromium.',
870 ),
871 True,
872 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
873 ),
874 (
875 r'/\bstd::function\b',
876 (
877 'std::function is banned. Instead use base::Callback which directly',
878 'supports Chromium\'s weak pointers, ref counting and more.',
879 ),
Peter Kasting991618a62019-06-17 22:00:09880 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21881 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
882 ),
883 (
884 r'/\b#include <random>\b',
885 (
886 'Do not use any random number engines from <random>. Instead',
887 'use base::RandomBitGenerator.',
888 ),
889 True,
890 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
891 ),
892 (
893 r'/\bstd::ratio\b',
894 (
895 'std::ratio is banned by the Google Style Guide.',
896 ),
897 True,
898 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45899 ),
900 (
Francois Doray43670e32017-09-27 12:40:38901 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
902 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
903 (
904 'Use the new API in base/threading/thread_restrictions.h.',
905 ),
Gabriel Charette04b138f2018-08-06 00:03:22906 False,
Francois Doray43670e32017-09-27 12:40:38907 (),
908 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38909 (
danakj7a2b7082019-05-21 21:13:51910 r'/\bbase::Bind\(',
911 (
912 'Please use base::Bind{Once,Repeating} instead',
913 'of base::Bind. (crbug.com/714018)',
914 ),
915 False,
916 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
917 ),
918 (
919 r'/\bbase::Callback[<:]',
920 (
921 'Please use base::{Once,Repeating}Callback instead',
922 'of base::Callback. (crbug.com/714018)',
923 ),
924 False,
925 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
926 ),
927 (
928 r'/\bbase::Closure\b',
929 (
930 'Please use base::{Once,Repeating}Closure instead',
931 'of base::Closure. (crbug.com/714018)',
932 ),
933 False,
934 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
935 ),
936 (
Alex Ilin5929abe32019-04-03 17:09:34937 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45938 (
939 'base::SharedMemory is deprecated. Please use',
940 '{Writable,ReadOnly}SharedMemoryRegion instead.',
941 ),
942 False,
943 (),
944 ),
945 (
Michael Giuffrida7f93d6922019-04-19 14:39:58946 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19947 (
948 'RunMessageLoop is deprecated, use RunLoop instead.',
949 ),
950 False,
951 (),
952 ),
953 (
Dave Tapuska98199b612019-07-10 13:30:44954 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19955 (
956 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
957 ),
958 False,
959 (),
960 ),
961 (
Dave Tapuska98199b612019-07-10 13:30:44962 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19963 (
964 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
965 "if you're convinced you need this.",
966 ),
967 False,
968 (),
969 ),
970 (
Dave Tapuska98199b612019-07-10 13:30:44971 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19972 (
973 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04974 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19975 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
976 'async events instead of flushing threads.',
977 ),
978 False,
979 (),
980 ),
981 (
982 r'MessageLoopRunner',
983 (
984 'MessageLoopRunner is deprecated, use RunLoop instead.',
985 ),
986 False,
987 (),
988 ),
989 (
Dave Tapuska98199b612019-07-10 13:30:44990 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19991 (
992 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
993 "gab@ if you found a use case where this is the only solution.",
994 ),
995 False,
996 (),
997 ),
998 (
Victor Costane48a2e82019-03-15 22:02:34999 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161000 (
Victor Costane48a2e82019-03-15 22:02:341001 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161002 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1003 ),
1004 True,
1005 (
1006 r'^sql/initialization\.(cc|h)$',
1007 r'^third_party/sqlite/.*\.(c|cc|h)$',
1008 ),
1009 ),
Matt Menke7f520a82018-03-28 21:38:371010 (
1011 'net::URLFetcher',
1012 (
1013 'net::URLFetcher should no longer be used in content embedders. ',
1014 'Instead, use network::SimpleURLLoader instead, which supports ',
1015 'an out-of-process network stack. ',
1016 'net::URLFetcher may still be used in binaries that do not embed',
1017 'content.',
1018 ),
Matt Menke59716d02018-04-05 12:45:531019 False,
Matt Menke7f520a82018-03-28 21:38:371020 (
Egor Paskoce145c42018-09-28 19:31:041021 r'^ios[\\/].*\.(cc|h)$',
1022 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:371023 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:041024 r'^net[\\/].*\.(cc|h)$',
1025 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Fabrice de Gans-Riberi9345311c2019-08-30 23:33:431026 r'^fuchsia/base/test_devtools_list_fetcher\.cc$',
Matt Menke7f520a82018-03-28 21:38:371027 ),
1028 ),
jdoerried7d10ab2018-04-27 10:46:131029 (
Dave Tapuska98199b612019-07-10 13:30:441030 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471031 (
1032 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1033 'base::RandomShuffle instead.'
1034 ),
1035 True,
1036 (),
1037 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241038 (
1039 'ios/web/public/test/http_server',
1040 (
1041 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1042 ),
1043 False,
1044 (),
1045 ),
Robert Liao764c9492019-01-24 18:46:281046 (
1047 'GetAddressOf',
1048 (
1049 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1050 'implicated in a few leaks. Use operator& instead.'
1051 ),
1052 True,
1053 (),
1054 ),
Antonio Gomes07300d02019-03-13 20:59:571055 (
1056 'DEFINE_TYPE_CASTS',
1057 (
1058 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
1059 '//third_party/blink/renderer/platform/casting.h.'
1060 ),
1061 True,
1062 (
1063 r'^third_party/blink/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381066 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371067 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381068 (
1069 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1070 ),
1071 True,
1072 (),
1073 ),
Ben Lewisa9514602019-04-29 17:53:051074 (
1075 'SHFileOperation',
1076 (
1077 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1078 'complex functions to achieve the same goals. Use IFileOperation for ',
1079 'any esoteric actions instead.'
1080 ),
1081 True,
1082 (),
1083 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181084 (
Cliff Smolinsky81951642019-04-30 21:39:511085 'StringFromGUID2',
1086 (
1087 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1088 'Use base::win::String16FromGUID instead.'
1089 ),
1090 True,
1091 (
1092 r'/base/win/win_util_unittest.cc'
1093 ),
1094 ),
1095 (
1096 'StringFromCLSID',
1097 (
1098 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1099 'Use base::win::String16FromGUID instead.'
1100 ),
1101 True,
1102 (
1103 r'/base/win/win_util_unittest.cc'
1104 ),
1105 ),
1106 (
Avi Drissman7382afa02019-04-29 23:27:131107 'kCFAllocatorNull',
1108 (
1109 'The use of kCFAllocatorNull with the NoCopy creation of ',
1110 'CoreFoundation types is prohibited.',
1111 ),
1112 True,
1113 (),
1114 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291115 (
1116 'mojo::ConvertTo',
1117 (
1118 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1119 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1120 'StringTraits if you would like to convert between custom types and',
1121 'the wire format of mojom types.'
1122 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221123 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291124 (
Wezf89dec092019-09-11 19:38:331125 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1126 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291127 r'^third_party/blink/.*\.(cc|h)$',
1128 r'^content/renderer/.*\.(cc|h)$',
1129 ),
1130 ),
[email protected]127f18ec2012-06-16 05:05:591131)
1132
wnwenbdc444e2016-05-25 13:44:151133
mlamouria82272622014-09-16 18:45:041134_IPC_ENUM_TRAITS_DEPRECATED = (
1135 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501136 'See http://www.chromium.org/Home/chromium-security/education/'
1137 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041138
Stephen Martinis97a394142018-06-07 23:06:051139_LONG_PATH_ERROR = (
1140 'Some files included in this CL have file names that are too long (> 200'
1141 ' characters). If committed, these files will cause issues on Windows. See'
1142 ' https://crbug.com/612667 for more details.'
1143)
1144
Shenghua Zhangbfaa38b82017-11-16 21:58:021145_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041146 r".*[\\/]BuildHooksAndroidImpl\.java",
1147 r".*[\\/]LicenseContentProvider\.java",
1148 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281149 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021150]
[email protected]127f18ec2012-06-16 05:05:591151
Sean Kau46e29bc2017-08-28 16:31:161152# These paths contain test data and other known invalid JSON files.
1153_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041154 r'test[\\/]data[\\/]',
1155 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1156 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041157 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431158 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161159]
1160
1161
[email protected]b00342e7f2013-03-26 16:21:541162_VALID_OS_MACROS = (
1163 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081164 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541165 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121166 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541167 'OS_BSD',
1168 'OS_CAT', # For testing.
1169 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041170 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541171 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371172 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541173 'OS_IOS',
1174 'OS_LINUX',
1175 'OS_MACOSX',
1176 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211177 'OS_NACL_NONSFI',
1178 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121179 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541180 'OS_OPENBSD',
1181 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371182 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541183 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541184 'OS_WIN',
1185)
1186
1187
agrievef32bcc72016-04-04 14:57:401188_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391189 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361190 'base/android/jni_generator/jni_generator.pydeps',
1191 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221192 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361193 'build/android/gyp/aar.pydeps',
1194 'build/android/gyp/aidl.pydeps',
1195 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381196 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361197 'build/android/gyp/bytecode_processor.pydeps',
1198 'build/android/gyp/compile_resources.pydeps',
Tibor Goldschwendt84ec04c2019-08-23 21:19:091199 'build/android/gyp/create_app_bundle_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361200 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1201 'build/android/gyp/copy_ex.pydeps',
1202 'build/android/gyp/create_app_bundle.pydeps',
1203 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361204 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221205 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361206 'build/android/gyp/create_tool_wrapper.pydeps',
1207 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591208 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361209 'build/android/gyp/dex.pydeps',
1210 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361211 'build/android/gyp/filter_zip.pydeps',
1212 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361213 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361214 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581215 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361216 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261217 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361218 'build/android/gyp/javac.pydeps',
1219 'build/android/gyp/jinja_template.pydeps',
1220 'build/android/gyp/lint.pydeps',
1221 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361222 'build/android/gyp/merge_manifest.pydeps',
1223 'build/android/gyp/prepare_resources.pydeps',
1224 'build/android/gyp/proguard.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241225 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361226 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461227 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561228 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361229 'build/android/incremental_install/generate_android_manifest.pydeps',
1230 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221231 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401232 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041233 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361234 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411235 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:191236 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021237 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:401238]
1239
wnwenbdc444e2016-05-25 13:44:151240
agrievef32bcc72016-04-04 14:57:401241_GENERIC_PYDEPS_FILES = [
anthonyvd7323c982019-09-11 14:36:421242 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131243 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421244 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1245 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131246 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061247 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221248 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401249]
1250
wnwenbdc444e2016-05-25 13:44:151251
agrievef32bcc72016-04-04 14:57:401252_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1253
1254
Eric Boren6fd2b932018-01-25 15:05:081255# Bypass the AUTHORS check for these accounts.
1256_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:291257 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
1258 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:081259 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:321260 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:591261 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451262 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591263 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:221264 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041265 ) | set('%[email protected]' % s
1266 for s in ('chromium-autoroll',)
1267 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301268 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081269
1270
Daniel Bratell65b033262019-04-23 08:17:061271def _IsCPlusPlusFile(input_api, file_path):
1272 """Returns True if this file contains C++-like code (and not Python,
1273 Go, Java, MarkDown, ...)"""
1274
1275 ext = input_api.os_path.splitext(file_path)[1]
1276 # This list is compatible with CppChecker.IsCppFile but we should
1277 # consider adding ".c" to it. If we do that we can use this function
1278 # at more places in the code.
1279 return ext in (
1280 '.h',
1281 '.cc',
1282 '.cpp',
1283 '.m',
1284 '.mm',
1285 )
1286
1287def _IsCPlusPlusHeaderFile(input_api, file_path):
1288 return input_api.os_path.splitext(file_path)[1] == ".h"
1289
1290
1291def _IsJavaFile(input_api, file_path):
1292 return input_api.os_path.splitext(file_path)[1] == ".java"
1293
1294
1295def _IsProtoFile(input_api, file_path):
1296 return input_api.os_path.splitext(file_path)[1] == ".proto"
1297
[email protected]55459852011-08-10 15:17:191298def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1299 """Attempts to prevent use of functions intended only for testing in
1300 non-testing code. For now this is just a best-effort implementation
1301 that ignores header files and may have some false positives. A
1302 better implementation would probably need a proper C++ parser.
1303 """
1304 # We only scan .cc files and the like, as the declaration of
1305 # for-testing functions in header files are hard to distinguish from
1306 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491307 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191308
jochenc0d4808c2015-07-27 09:25:421309 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191310 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091311 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191312 exclusion_pattern = input_api.re.compile(
1313 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1314 base_function_pattern, base_function_pattern))
1315
1316 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441317 black_list = (_EXCLUDED_PATHS +
1318 _TEST_CODE_EXCLUDED_PATHS +
1319 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191320 return input_api.FilterSourceFile(
1321 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491322 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191323 black_list=black_list)
1324
1325 problems = []
1326 for f in input_api.AffectedSourceFiles(FilterFile):
1327 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241328 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031329 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461330 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031331 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191332 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031333 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191334
1335 if problems:
[email protected]f7051d52013-04-02 18:31:421336 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031337 else:
1338 return []
[email protected]55459852011-08-10 15:17:191339
1340
Vaclav Brozek7dbc28c2018-03-27 08:35:231341def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1342 """This is a simplified version of
1343 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1344 """
1345 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1346 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1347 name_pattern = r'ForTest(s|ing)?'
1348 # Describes an occurrence of "ForTest*" inside a // comment.
1349 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1350 # Catch calls.
1351 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1352 # Ignore definitions. (Comments are ignored separately.)
1353 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1354
1355 problems = []
1356 sources = lambda x: input_api.FilterSourceFile(
1357 x,
1358 black_list=(('(?i).*test', r'.*\/junit\/')
1359 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491360 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231361 )
1362 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1363 local_path = f.LocalPath()
1364 is_inside_javadoc = False
1365 for line_number, line in f.ChangedContents():
1366 if is_inside_javadoc and javadoc_end_re.search(line):
1367 is_inside_javadoc = False
1368 if not is_inside_javadoc and javadoc_start_re.search(line):
1369 is_inside_javadoc = True
1370 if is_inside_javadoc:
1371 continue
1372 if (inclusion_re.search(line) and
1373 not comment_re.search(line) and
1374 not exclusion_re.search(line)):
1375 problems.append(
1376 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1377
1378 if problems:
1379 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1380 else:
1381 return []
1382
1383
[email protected]10689ca2011-09-02 02:31:541384def _CheckNoIOStreamInHeaders(input_api, output_api):
1385 """Checks to make sure no .h files include <iostream>."""
1386 files = []
1387 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1388 input_api.re.MULTILINE)
1389 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1390 if not f.LocalPath().endswith('.h'):
1391 continue
1392 contents = input_api.ReadFile(f)
1393 if pattern.search(contents):
1394 files.append(f)
1395
1396 if len(files):
yolandyandaabc6d2016-04-18 18:29:391397 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061398 'Do not #include <iostream> in header files, since it inserts static '
1399 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541400 '#include <ostream>. See http://crbug.com/94794',
1401 files) ]
1402 return []
1403
Danil Chapovalov3518f362018-08-11 16:13:431404def _CheckNoStrCatRedefines(input_api, output_api):
1405 """Checks no windows headers with StrCat redefined are included directly."""
1406 files = []
1407 pattern_deny = input_api.re.compile(
1408 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1409 input_api.re.MULTILINE)
1410 pattern_allow = input_api.re.compile(
1411 r'^#include\s"base/win/windows_defines.inc"',
1412 input_api.re.MULTILINE)
1413 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1414 contents = input_api.ReadFile(f)
1415 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1416 files.append(f.LocalPath())
1417
1418 if len(files):
1419 return [output_api.PresubmitError(
1420 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1421 'directly since they pollute code with StrCat macro. Instead, '
1422 'include matching header from base/win. See http://crbug.com/856536',
1423 files) ]
1424 return []
1425
[email protected]10689ca2011-09-02 02:31:541426
[email protected]72df4e782012-06-21 16:28:181427def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521428 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181429 problems = []
1430 for f in input_api.AffectedFiles():
1431 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1432 continue
1433
1434 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041435 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181436 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1437
1438 if not problems:
1439 return []
1440 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1441 '\n'.join(problems))]
1442
Dominic Battre033531052018-09-24 15:45:341443def _CheckNoDISABLETypoInTests(input_api, output_api):
1444 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1445
1446 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1447 instead of DISABLED_. To filter false positives, reports are only generated
1448 if a corresponding MAYBE_ line exists.
1449 """
1450 problems = []
1451
1452 # The following two patterns are looked for in tandem - is a test labeled
1453 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1454 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1455 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1456
1457 # This is for the case that a test is disabled on all platforms.
1458 full_disable_pattern = input_api.re.compile(
1459 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1460 input_api.re.MULTILINE)
1461
Katie Df13948e2018-09-25 07:33:441462 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341463 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1464 continue
1465
1466 # Search for MABYE_, DISABLE_ pairs.
1467 disable_lines = {} # Maps of test name to line number.
1468 maybe_lines = {}
1469 for line_num, line in f.ChangedContents():
1470 disable_match = disable_pattern.search(line)
1471 if disable_match:
1472 disable_lines[disable_match.group(1)] = line_num
1473 maybe_match = maybe_pattern.search(line)
1474 if maybe_match:
1475 maybe_lines[maybe_match.group(1)] = line_num
1476
1477 # Search for DISABLE_ occurrences within a TEST() macro.
1478 disable_tests = set(disable_lines.keys())
1479 maybe_tests = set(maybe_lines.keys())
1480 for test in disable_tests.intersection(maybe_tests):
1481 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1482
1483 contents = input_api.ReadFile(f)
1484 full_disable_match = full_disable_pattern.search(contents)
1485 if full_disable_match:
1486 problems.append(' %s' % f.LocalPath())
1487
1488 if not problems:
1489 return []
1490 return [
1491 output_api.PresubmitPromptWarning(
1492 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1493 '\n'.join(problems))
1494 ]
1495
[email protected]72df4e782012-06-21 16:28:181496
danakj61c1aa22015-10-26 19:55:521497def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571498 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521499 errors = []
1500 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1501 input_api.re.MULTILINE)
1502 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1503 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1504 continue
1505 for lnum, line in f.ChangedContents():
1506 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171507 errors.append(output_api.PresubmitError(
1508 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571509 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171510 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521511 return errors
1512
1513
Makoto Shimazu3ad422cd2019-05-08 02:35:141514def _FindHistogramNameInChunk(histogram_name, chunk):
1515 """Tries to find a histogram name or prefix in a line.
1516
1517 Returns the existence of the histogram name, or None if it needs more chunk
1518 to determine."""
mcasasb7440c282015-02-04 14:52:191519 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1520 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141521 if '<affected-histogram' in chunk:
1522 # If the tag is not completed, needs more chunk to get the name.
1523 if not '>' in chunk:
1524 return None
1525 if not 'name="' in chunk:
1526 return False
1527 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1528 # expect the only attribute is the name.
1529 histogram_prefix = chunk.split('"')[1]
1530 return histogram_prefix in histogram_name
1531 # Typically the whole histogram name should in the line.
1532 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191533
1534
1535def _CheckUmaHistogramChanges(input_api, output_api):
1536 """Check that UMA histogram names in touched lines can still be found in other
1537 lines of the patch or in histograms.xml. Note that this check would not catch
1538 the reverse: changes in histograms.xml not matched in the code itself."""
1539 touched_histograms = []
1540 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471541 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1542 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1543 name_pattern = r'"(.*?)"'
1544 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1545 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1546 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1547 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1548 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171549 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191550 for f in input_api.AffectedFiles():
1551 # If histograms.xml itself is modified, keep the modified lines for later.
1552 if f.LocalPath().endswith(('histograms.xml')):
1553 histograms_xml_modifications = f.ChangedContents()
1554 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471555 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1556 single_line_re = single_line_c_re
1557 split_line_prefix_re = split_line_c_prefix_re
1558 elif f.LocalPath().endswith(('java')):
1559 single_line_re = single_line_java_re
1560 split_line_prefix_re = split_line_java_prefix_re
1561 else:
mcasasb7440c282015-02-04 14:52:191562 continue
1563 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171564 if last_line_matched_prefix:
1565 suffix_found = split_line_suffix_re.search(line)
1566 if suffix_found :
1567 touched_histograms.append([suffix_found.group(1), f, line_num])
1568 last_line_matched_prefix = False
1569 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061570 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191571 if found:
1572 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171573 continue
1574 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191575
1576 # Search for the touched histogram names in the local modifications to
1577 # histograms.xml, and, if not found, on the base histograms.xml file.
1578 unmatched_histograms = []
1579 for histogram_info in touched_histograms:
1580 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141581 chunk = ''
mcasasb7440c282015-02-04 14:52:191582 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141583 chunk += line
1584 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1585 if histogram_name_found is None:
1586 continue
1587 chunk = ''
mcasasb7440c282015-02-04 14:52:191588 if histogram_name_found:
1589 break
1590 if not histogram_name_found:
1591 unmatched_histograms.append(histogram_info)
1592
eromanb90c82e7e32015-04-01 15:13:491593 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191594 problems = []
1595 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491596 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191597 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451598 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191599 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141600 chunk = ''
mcasasb7440c282015-02-04 14:52:191601 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141602 chunk += line
1603 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1604 chunk)
1605 if histogram_name_found is None:
1606 continue
1607 chunk = ''
mcasasb7440c282015-02-04 14:52:191608 if histogram_name_found:
1609 break
1610 if not histogram_name_found:
1611 problems.append(' [%s:%d] %s' %
1612 (f.LocalPath(), line_num, histogram_name))
1613
1614 if not problems:
1615 return []
1616 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1617 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491618 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191619
wnwenbdc444e2016-05-25 13:44:151620
yolandyandaabc6d2016-04-18 18:29:391621def _CheckFlakyTestUsage(input_api, output_api):
1622 """Check that FlakyTest annotation is our own instead of the android one"""
1623 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1624 files = []
1625 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1626 if f.LocalPath().endswith('Test.java'):
1627 if pattern.search(input_api.ReadFile(f)):
1628 files.append(f)
1629 if len(files):
1630 return [output_api.PresubmitError(
1631 'Use org.chromium.base.test.util.FlakyTest instead of '
1632 'android.test.FlakyTest',
1633 files)]
1634 return []
mcasasb7440c282015-02-04 14:52:191635
wnwenbdc444e2016-05-25 13:44:151636
[email protected]8ea5d4b2011-09-13 21:49:221637def _CheckNoNewWStrings(input_api, output_api):
1638 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271639 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221640 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201641 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571642 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341643 '/win/' in f.LocalPath() or
1644 'chrome_elf' in f.LocalPath() or
1645 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201646 continue
[email protected]8ea5d4b2011-09-13 21:49:221647
[email protected]a11dbe9b2012-08-07 01:32:581648 allowWString = False
[email protected]b5c24292011-11-28 14:38:201649 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581650 if 'presubmit: allow wstring' in line:
1651 allowWString = True
1652 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271653 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581654 allowWString = False
1655 else:
1656 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221657
[email protected]55463aa62011-10-12 00:48:271658 if not problems:
1659 return []
1660 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581661 ' If you are calling a cross-platform API that accepts a wstring, '
1662 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271663 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221664
1665
[email protected]2a8ac9c2011-10-19 17:20:441666def _CheckNoDEPSGIT(input_api, output_api):
1667 """Make sure .DEPS.git is never modified manually."""
1668 if any(f.LocalPath().endswith('.DEPS.git') for f in
1669 input_api.AffectedFiles()):
1670 return [output_api.PresubmitError(
1671 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1672 'automated system based on what\'s in DEPS and your changes will be\n'
1673 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501674 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1675 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441676 'for more information')]
1677 return []
1678
1679
tandriief664692014-09-23 14:51:471680def _CheckValidHostsInDEPS(input_api, output_api):
1681 """Checks that DEPS file deps are from allowed_hosts."""
1682 # Run only if DEPS file has been modified to annoy fewer bystanders.
1683 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1684 return []
1685 # Outsource work to gclient verify
1686 try:
John Budorickf20c0042019-04-25 23:23:401687 gclient_path = input_api.os_path.join(
1688 input_api.PresubmitLocalPath(),
1689 'third_party', 'depot_tools', 'gclient.py')
1690 input_api.subprocess.check_output(
1691 [input_api.python_executable, gclient_path, 'verify'],
1692 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471693 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201694 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471695 return [output_api.PresubmitError(
1696 'DEPS file must have only git dependencies.',
1697 long_text=error.output)]
1698
1699
[email protected]127f18ec2012-06-16 05:05:591700def _CheckNoBannedFunctions(input_api, output_api):
1701 """Make sure that banned functions are not used."""
1702 warnings = []
1703 errors = []
1704
wnwenbdc444e2016-05-25 13:44:151705 def IsBlacklisted(affected_file, blacklist):
1706 local_path = affected_file.LocalPath()
1707 for item in blacklist:
1708 if input_api.re.match(item, local_path):
1709 return True
1710 return False
1711
Peter K. Lee6c03ccff2019-07-15 14:40:051712 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541713 local_path = affected_file.LocalPath()
1714 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1715 return False
1716 basename = input_api.os_path.basename(local_path)
1717 if 'ios' in basename.split('_'):
1718 return True
1719 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1720 if sep and 'ios' in local_path.split(sep):
1721 return True
1722 return False
1723
wnwenbdc444e2016-05-25 13:44:151724 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1725 matched = False
1726 if func_name[0:1] == '/':
1727 regex = func_name[1:]
1728 if input_api.re.search(regex, line):
1729 matched = True
1730 elif func_name in line:
dchenge07de812016-06-20 19:27:171731 matched = True
wnwenbdc444e2016-05-25 13:44:151732 if matched:
dchenge07de812016-06-20 19:27:171733 problems = warnings
wnwenbdc444e2016-05-25 13:44:151734 if error:
dchenge07de812016-06-20 19:27:171735 problems = errors
wnwenbdc444e2016-05-25 13:44:151736 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1737 for message_line in message:
1738 problems.append(' %s' % message_line)
1739
Eric Stevensona9a980972017-09-23 00:04:411740 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1741 for f in input_api.AffectedFiles(file_filter=file_filter):
1742 for line_num, line in f.ChangedContents():
1743 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1744 CheckForMatch(f, line_num, line, func_name, message, error)
1745
[email protected]127f18ec2012-06-16 05:05:591746 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1747 for f in input_api.AffectedFiles(file_filter=file_filter):
1748 for line_num, line in f.ChangedContents():
1749 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151750 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591751
Peter K. Lee6c03ccff2019-07-15 14:40:051752 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541753 for line_num, line in f.ChangedContents():
1754 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1755 CheckForMatch(f, line_num, line, func_name, message, error)
1756
Peter K. Lee6c03ccff2019-07-15 14:40:051757 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1758 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1759 for line_num, line in f.ChangedContents():
1760 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1761 CheckForMatch(f, line_num, line, func_name, message, error)
1762
[email protected]127f18ec2012-06-16 05:05:591763 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1764 for f in input_api.AffectedFiles(file_filter=file_filter):
1765 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491766 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491767 if IsBlacklisted(f, excluded_paths):
1768 continue
wnwenbdc444e2016-05-25 13:44:151769 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591770
1771 result = []
1772 if (warnings):
1773 result.append(output_api.PresubmitPromptWarning(
1774 'Banned functions were used.\n' + '\n'.join(warnings)))
1775 if (errors):
1776 result.append(output_api.PresubmitError(
1777 'Banned functions were used.\n' + '\n'.join(errors)))
1778 return result
1779
1780
[email protected]6c063c62012-07-11 19:11:061781def _CheckNoPragmaOnce(input_api, output_api):
1782 """Make sure that banned functions are not used."""
1783 files = []
1784 pattern = input_api.re.compile(r'^#pragma\s+once',
1785 input_api.re.MULTILINE)
1786 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1787 if not f.LocalPath().endswith('.h'):
1788 continue
1789 contents = input_api.ReadFile(f)
1790 if pattern.search(contents):
1791 files.append(f)
1792
1793 if files:
1794 return [output_api.PresubmitError(
1795 'Do not use #pragma once in header files.\n'
1796 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1797 files)]
1798 return []
1799
[email protected]127f18ec2012-06-16 05:05:591800
[email protected]e7479052012-09-19 00:26:121801def _CheckNoTrinaryTrueFalse(input_api, output_api):
1802 """Checks to make sure we don't introduce use of foo ? true : false."""
1803 problems = []
1804 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1805 for f in input_api.AffectedFiles():
1806 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1807 continue
1808
1809 for line_num, line in f.ChangedContents():
1810 if pattern.match(line):
1811 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1812
1813 if not problems:
1814 return []
1815 return [output_api.PresubmitPromptWarning(
1816 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1817 '\n'.join(problems))]
1818
1819
[email protected]55f9f382012-07-31 11:02:181820def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281821 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181822 change. Breaking - rules is an error, breaking ! rules is a
1823 warning.
1824 """
mohan.reddyf21db962014-10-16 12:26:471825 import sys
[email protected]55f9f382012-07-31 11:02:181826 # We need to wait until we have an input_api object and use this
1827 # roundabout construct to import checkdeps because this file is
1828 # eval-ed and thus doesn't have __file__.
1829 original_sys_path = sys.path
1830 try:
1831 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471832 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181833 import checkdeps
[email protected]55f9f382012-07-31 11:02:181834 from rules import Rule
1835 finally:
1836 # Restore sys.path to what it was before.
1837 sys.path = original_sys_path
1838
1839 added_includes = []
rhalavati08acd232017-04-03 07:23:281840 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241841 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181842 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061843 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501844 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081845 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061846 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501847 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081848 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061849 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501850 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081851 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181852
[email protected]26385172013-05-09 23:11:351853 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181854
1855 error_descriptions = []
1856 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281857 error_subjects = set()
1858 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181859 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1860 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081861 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181862 description_with_path = '%s\n %s' % (path, rule_description)
1863 if rule_type == Rule.DISALLOW:
1864 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281865 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181866 else:
1867 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281868 warning_subjects.add("#includes")
1869
1870 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1871 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081872 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281873 description_with_path = '%s\n %s' % (path, rule_description)
1874 if rule_type == Rule.DISALLOW:
1875 error_descriptions.append(description_with_path)
1876 error_subjects.add("imports")
1877 else:
1878 warning_descriptions.append(description_with_path)
1879 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181880
Jinsuk Kim5a092672017-10-24 22:42:241881 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021882 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081883 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241884 description_with_path = '%s\n %s' % (path, rule_description)
1885 if rule_type == Rule.DISALLOW:
1886 error_descriptions.append(description_with_path)
1887 error_subjects.add("imports")
1888 else:
1889 warning_descriptions.append(description_with_path)
1890 warning_subjects.add("imports")
1891
[email protected]55f9f382012-07-31 11:02:181892 results = []
1893 if error_descriptions:
1894 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281895 'You added one or more %s that violate checkdeps rules.'
1896 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181897 error_descriptions))
1898 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421899 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281900 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181901 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281902 '%s? See relevant DEPS file(s) for details and contacts.' %
1903 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181904 warning_descriptions))
1905 return results
1906
1907
[email protected]fbcafe5a2012-08-08 15:31:221908def _CheckFilePermissions(input_api, output_api):
1909 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151910 if input_api.platform == 'win32':
1911 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291912 checkperms_tool = input_api.os_path.join(
1913 input_api.PresubmitLocalPath(),
1914 'tools', 'checkperms', 'checkperms.py')
1915 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471916 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391917 with input_api.CreateTemporaryFile() as file_list:
1918 for f in input_api.AffectedFiles():
1919 # checkperms.py file/directory arguments must be relative to the
1920 # repository.
1921 file_list.write(f.LocalPath() + '\n')
1922 file_list.close()
1923 args += ['--file-list', file_list.name]
1924 try:
1925 input_api.subprocess.check_output(args)
1926 return []
1927 except input_api.subprocess.CalledProcessError as error:
1928 return [output_api.PresubmitError(
1929 'checkperms.py failed:',
1930 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221931
1932
robertocn832f5992017-01-04 19:01:301933def _CheckTeamTags(input_api, output_api):
1934 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1935 checkteamtags_tool = input_api.os_path.join(
1936 input_api.PresubmitLocalPath(),
1937 'tools', 'checkteamtags', 'checkteamtags.py')
1938 args = [input_api.python_executable, checkteamtags_tool,
1939 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221940 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301941 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1942 'OWNERS']
1943 try:
1944 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:051945 warnings = input_api.subprocess.check_output(args + files).splitlines()
1946 if warnings:
1947 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:301948 return []
1949 except input_api.subprocess.CalledProcessError as error:
1950 return [output_api.PresubmitError(
1951 'checkteamtags.py failed:',
1952 long_text=error.output)]
1953
1954
[email protected]c8278b32012-10-30 20:35:491955def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1956 """Makes sure we don't include ui/aura/window_property.h
1957 in header files.
1958 """
1959 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1960 errors = []
1961 for f in input_api.AffectedFiles():
1962 if not f.LocalPath().endswith('.h'):
1963 continue
1964 for line_num, line in f.ChangedContents():
1965 if pattern.match(line):
1966 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1967
1968 results = []
1969 if errors:
1970 results.append(output_api.PresubmitError(
1971 'Header files should not include ui/aura/window_property.h', errors))
1972 return results
1973
1974
[email protected]70ca77752012-11-20 03:45:031975def _CheckForVersionControlConflictsInFile(input_api, f):
1976 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1977 errors = []
1978 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161979 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231980 # First-level headers in markdown look a lot like version control
1981 # conflict markers. http://daringfireball.net/projects/markdown/basics
1982 continue
[email protected]70ca77752012-11-20 03:45:031983 if pattern.match(line):
1984 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1985 return errors
1986
1987
1988def _CheckForVersionControlConflicts(input_api, output_api):
1989 """Usually this is not intentional and will cause a compile failure."""
1990 errors = []
1991 for f in input_api.AffectedFiles():
1992 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1993
1994 results = []
1995 if errors:
1996 results.append(output_api.PresubmitError(
1997 'Version control conflict markers found, please resolve.', errors))
1998 return results
1999
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202000
estadee17314a02017-01-12 16:22:162001def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2002 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2003 errors = []
2004 for f in input_api.AffectedFiles():
2005 for line_num, line in f.ChangedContents():
2006 if pattern.search(line):
2007 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2008
2009 results = []
2010 if errors:
2011 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502012 'Found Google support URL addressed by answer number. Please replace '
2013 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162014 return results
2015
[email protected]70ca77752012-11-20 03:45:032016
[email protected]06e6d0ff2012-12-11 01:36:442017def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2018 def FilterFile(affected_file):
2019 """Filter function for use with input_api.AffectedSourceFiles,
2020 below. This filters out everything except non-test files from
2021 top-level directories that generally speaking should not hard-code
2022 service URLs (e.g. src/android_webview/, src/content/ and others).
2023 """
2024 return input_api.FilterSourceFile(
2025 affected_file,
Egor Paskoce145c42018-09-28 19:31:042026 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442027 black_list=(_EXCLUDED_PATHS +
2028 _TEST_CODE_EXCLUDED_PATHS +
2029 input_api.DEFAULT_BLACK_LIST))
2030
reillyi38965732015-11-16 18:27:332031 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2032 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462033 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2034 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442035 problems = [] # items are (filename, line_number, line)
2036 for f in input_api.AffectedSourceFiles(FilterFile):
2037 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462038 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442039 problems.append((f.LocalPath(), line_num, line))
2040
2041 if problems:
[email protected]f7051d52013-04-02 18:31:422042 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442043 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582044 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442045 [' %s:%d: %s' % (
2046 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032047 else:
2048 return []
[email protected]06e6d0ff2012-12-11 01:36:442049
2050
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492051# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272052def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2053 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312054 The native_client_sdk directory is excluded because it has auto-generated PNG
2055 files for documentation.
[email protected]d2530012013-01-25 16:39:272056 """
[email protected]d2530012013-01-25 16:39:272057 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492058 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042059 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312060 file_filter = lambda f: input_api.FilterSourceFile(
2061 f, white_list=white_list, black_list=black_list)
2062 for f in input_api.AffectedFiles(include_deletes=False,
2063 file_filter=file_filter):
2064 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272065
2066 results = []
2067 if errors:
2068 results.append(output_api.PresubmitError(
2069 'The name of PNG files should not have abbreviations. \n'
2070 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2071 'Contact [email protected] if you have questions.', errors))
2072 return results
2073
2074
Daniel Cheng4dcdb6b2017-04-13 08:30:172075def _ExtractAddRulesFromParsedDeps(parsed_deps):
2076 """Extract the rules that add dependencies from a parsed DEPS file.
2077
2078 Args:
2079 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2080 add_rules = set()
2081 add_rules.update([
2082 rule[1:] for rule in parsed_deps.get('include_rules', [])
2083 if rule.startswith('+') or rule.startswith('!')
2084 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502085 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172086 {}).iteritems():
2087 add_rules.update([
2088 rule[1:] for rule in rules
2089 if rule.startswith('+') or rule.startswith('!')
2090 ])
2091 return add_rules
2092
2093
2094def _ParseDeps(contents):
2095 """Simple helper for parsing DEPS files."""
2096 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172097 class _VarImpl:
2098
2099 def __init__(self, local_scope):
2100 self._local_scope = local_scope
2101
2102 def Lookup(self, var_name):
2103 """Implements the Var syntax."""
2104 try:
2105 return self._local_scope['vars'][var_name]
2106 except KeyError:
2107 raise Exception('Var is not defined: %s' % var_name)
2108
2109 local_scope = {}
2110 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172111 'Var': _VarImpl(local_scope).Lookup,
2112 }
2113 exec contents in global_scope, local_scope
2114 return local_scope
2115
2116
2117def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082118 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412119 a set of DEPS entries that we should look up.
2120
2121 For a directory (rather than a specific filename) we fake a path to
2122 a specific filename by adding /DEPS. This is chosen as a file that
2123 will seldom or never be subject to per-file include_rules.
2124 """
[email protected]2b438d62013-11-14 17:54:142125 # We ignore deps entries on auto-generated directories.
2126 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082127
Daniel Cheng4dcdb6b2017-04-13 08:30:172128 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2129 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2130
2131 added_deps = new_deps.difference(old_deps)
2132
[email protected]2b438d62013-11-14 17:54:142133 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172134 for added_dep in added_deps:
2135 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2136 continue
2137 # Assume that a rule that ends in .h is a rule for a specific file.
2138 if added_dep.endswith('.h'):
2139 results.add(added_dep)
2140 else:
2141 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082142 return results
2143
2144
[email protected]e871964c2013-05-13 14:14:552145def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2146 """When a dependency prefixed with + is added to a DEPS file, we
2147 want to make sure that the change is reviewed by an OWNER of the
2148 target file or directory, to avoid layering violations from being
2149 introduced. This check verifies that this happens.
2150 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172151 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242152
2153 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492154 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242155 for f in input_api.AffectedFiles(include_deletes=False,
2156 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552157 filename = input_api.os_path.basename(f.LocalPath())
2158 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172159 virtual_depended_on_files.update(_CalculateAddedDeps(
2160 input_api.os_path,
2161 '\n'.join(f.OldContents()),
2162 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552163
[email protected]e871964c2013-05-13 14:14:552164 if not virtual_depended_on_files:
2165 return []
2166
2167 if input_api.is_committing:
2168 if input_api.tbr:
2169 return [output_api.PresubmitNotifyResult(
2170 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272171 if input_api.dry_run:
2172 return [output_api.PresubmitNotifyResult(
2173 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552174 if not input_api.change.issue:
2175 return [output_api.PresubmitError(
2176 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402177 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552178 output = output_api.PresubmitError
2179 else:
2180 output = output_api.PresubmitNotifyResult
2181
2182 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502183 owner_email, reviewers = (
2184 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2185 input_api,
2186 owners_db.email_regexp,
2187 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552188
2189 owner_email = owner_email or input_api.change.author_email
2190
[email protected]de4f7d22013-05-23 14:27:462191 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512192 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462193 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552194 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2195 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412196
2197 # We strip the /DEPS part that was added by
2198 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2199 # directory.
2200 def StripDeps(path):
2201 start_deps = path.rfind('/DEPS')
2202 if start_deps != -1:
2203 return path[:start_deps]
2204 else:
2205 return path
2206 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552207 for path in missing_files]
2208
2209 if unapproved_dependencies:
2210 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152211 output('You need LGTM from owners of depends-on paths in DEPS that were '
2212 'modified in this CL:\n %s' %
2213 '\n '.join(sorted(unapproved_dependencies)))]
2214 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2215 output_list.append(output(
2216 'Suggested missing target path OWNERS:\n %s' %
2217 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552218 return output_list
2219
2220 return []
2221
2222
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492223# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402224def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492225 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402226 black_list = (_EXCLUDED_PATHS +
2227 _TEST_CODE_EXCLUDED_PATHS +
2228 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042229 (r"^base[\\/]logging\.h$",
2230 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222231 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042232 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2233 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2234 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122235 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182236 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152237 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032238 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152239 r"^chrome[\\/]chrome_cleaner[\\/].*",
2240 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2241 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042242 r"^chromecast[\\/]",
2243 r"^cloud_print[\\/]",
2244 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482245 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:042246 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:312247 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042248 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462249 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042250 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462251 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042252 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252253 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042254 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2255 r"^courgette[\\/]courgette_tool\.cc$",
2256 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272257 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332258 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042259 r"^ipc[\\/]ipc_logging\.cc$",
2260 r"^native_client_sdk[\\/]",
2261 r"^remoting[\\/]base[\\/]logging\.h$",
2262 r"^remoting[\\/]host[\\/].*",
2263 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332264 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
2265 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042266 r"^tools[\\/]",
2267 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2268 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332269 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402270 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492271 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402272
thomasanderson625d3932017-03-29 07:16:582273 log_info = set([])
2274 printf = set([])
[email protected]85218562013-11-22 07:41:402275
2276 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582277 for _, line in f.ChangedContents():
2278 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2279 log_info.add(f.LocalPath())
2280 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2281 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372282
thomasanderson625d3932017-03-29 07:16:582283 if input_api.re.search(r"\bprintf\(", line):
2284 printf.add(f.LocalPath())
2285 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2286 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402287
2288 if log_info:
2289 return [output_api.PresubmitError(
2290 'These files spam the console log with LOG(INFO):',
2291 items=log_info)]
2292 if printf:
2293 return [output_api.PresubmitError(
2294 'These files spam the console log with printf/fprintf:',
2295 items=printf)]
2296 return []
2297
2298
[email protected]49aa76a2013-12-04 06:59:162299def _CheckForAnonymousVariables(input_api, output_api):
2300 """These types are all expected to hold locks while in scope and
2301 so should never be anonymous (which causes them to be immediately
2302 destroyed)."""
2303 they_who_must_be_named = [
2304 'base::AutoLock',
2305 'base::AutoReset',
2306 'base::AutoUnlock',
2307 'SkAutoAlphaRestore',
2308 'SkAutoBitmapShaderInstall',
2309 'SkAutoBlitterChoose',
2310 'SkAutoBounderCommit',
2311 'SkAutoCallProc',
2312 'SkAutoCanvasRestore',
2313 'SkAutoCommentBlock',
2314 'SkAutoDescriptor',
2315 'SkAutoDisableDirectionCheck',
2316 'SkAutoDisableOvalCheck',
2317 'SkAutoFree',
2318 'SkAutoGlyphCache',
2319 'SkAutoHDC',
2320 'SkAutoLockColors',
2321 'SkAutoLockPixels',
2322 'SkAutoMalloc',
2323 'SkAutoMaskFreeImage',
2324 'SkAutoMutexAcquire',
2325 'SkAutoPathBoundsUpdate',
2326 'SkAutoPDFRelease',
2327 'SkAutoRasterClipValidate',
2328 'SkAutoRef',
2329 'SkAutoTime',
2330 'SkAutoTrace',
2331 'SkAutoUnref',
2332 ]
2333 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2334 # bad: base::AutoLock(lock.get());
2335 # not bad: base::AutoLock lock(lock.get());
2336 bad_pattern = input_api.re.compile(anonymous)
2337 # good: new base::AutoLock(lock.get())
2338 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2339 errors = []
2340
2341 for f in input_api.AffectedFiles():
2342 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2343 continue
2344 for linenum, line in f.ChangedContents():
2345 if bad_pattern.search(line) and not good_pattern.search(line):
2346 errors.append('%s:%d' % (f.LocalPath(), linenum))
2347
2348 if errors:
2349 return [output_api.PresubmitError(
2350 'These lines create anonymous variables that need to be named:',
2351 items=errors)]
2352 return []
2353
2354
Peter Kasting4844e46e2018-02-23 07:27:102355def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532356 # Returns whether |template_str| is of the form <T, U...> for some types T
2357 # and U. Assumes that |template_str| is already in the form <...>.
2358 def HasMoreThanOneArg(template_str):
2359 # Level of <...> nesting.
2360 nesting = 0
2361 for c in template_str:
2362 if c == '<':
2363 nesting += 1
2364 elif c == '>':
2365 nesting -= 1
2366 elif c == ',' and nesting == 1:
2367 return True
2368 return False
2369
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492370 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102371 sources = lambda affected_file: input_api.FilterSourceFile(
2372 affected_file,
2373 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2374 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492375 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552376
2377 # Pattern to capture a single "<...>" block of template arguments. It can
2378 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2379 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2380 # latter would likely require counting that < and > match, which is not
2381 # expressible in regular languages. Should the need arise, one can introduce
2382 # limited counting (matching up to a total number of nesting depth), which
2383 # should cover all practical cases for already a low nesting limit.
2384 template_arg_pattern = (
2385 r'<[^>]*' # Opening block of <.
2386 r'>([^<]*>)?') # Closing block of >.
2387 # Prefix expressing that whatever follows is not already inside a <...>
2388 # block.
2389 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102390 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552391 not_inside_template_arg_pattern
2392 + r'\bstd::unique_ptr'
2393 + template_arg_pattern
2394 + r'\(\)')
2395
2396 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2397 template_arg_no_array_pattern = (
2398 r'<[^>]*[^]]' # Opening block of <.
2399 r'>([^(<]*[^]]>)?') # Closing block of >.
2400 # Prefix saying that what follows is the start of an expression.
2401 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2402 # Suffix saying that what follows are call parentheses with a non-empty list
2403 # of arguments.
2404 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532405 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552406 return_construct_pattern = input_api.re.compile(
2407 start_of_expr_pattern
2408 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532409 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552410 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532411 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552412 + nonempty_arg_list_pattern)
2413
Vaclav Brozek851d9602018-04-04 16:13:052414 problems_constructor = []
2415 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102416 for f in input_api.AffectedSourceFiles(sources):
2417 for line_number, line in f.ChangedContents():
2418 # Disallow:
2419 # return std::unique_ptr<T>(foo);
2420 # bar = std::unique_ptr<T>(foo);
2421 # But allow:
2422 # return std::unique_ptr<T[]>(foo);
2423 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532424 # And also allow cases when the second template argument is present. Those
2425 # cases cannot be handled by std::make_unique:
2426 # return std::unique_ptr<T, U>(foo);
2427 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052428 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532429 return_construct_result = return_construct_pattern.search(line)
2430 if return_construct_result and not HasMoreThanOneArg(
2431 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052432 problems_constructor.append(
2433 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102434 # Disallow:
2435 # std::unique_ptr<T>()
2436 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052437 problems_nullptr.append(
2438 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2439
2440 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162441 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052442 errors.append(output_api.PresubmitError(
2443 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162444 problems_nullptr))
2445 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052446 errors.append(output_api.PresubmitError(
2447 'The following files use explicit std::unique_ptr constructor.'
2448 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162449 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102450 return errors
2451
2452
[email protected]999261d2014-03-03 20:08:082453def _CheckUserActionUpdate(input_api, output_api):
2454 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522455 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082456 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522457 # If actions.xml is already included in the changelist, the PRESUBMIT
2458 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082459 return []
2460
[email protected]999261d2014-03-03 20:08:082461 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2462 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522463 current_actions = None
[email protected]999261d2014-03-03 20:08:082464 for f in input_api.AffectedFiles(file_filter=file_filter):
2465 for line_num, line in f.ChangedContents():
2466 match = input_api.re.search(action_re, line)
2467 if match:
[email protected]2f92dec2014-03-07 19:21:522468 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2469 # loaded only once.
2470 if not current_actions:
2471 with open('tools/metrics/actions/actions.xml') as actions_f:
2472 current_actions = actions_f.read()
2473 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082474 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522475 action = 'name="{0}"'.format(action_name)
2476 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082477 return [output_api.PresubmitPromptWarning(
2478 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522479 'tools/metrics/actions/actions.xml. Please run '
2480 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082481 % (f.LocalPath(), line_num, action_name))]
2482 return []
2483
2484
Daniel Cheng13ca61a882017-08-25 15:11:252485def _ImportJSONCommentEater(input_api):
2486 import sys
2487 sys.path = sys.path + [input_api.os_path.join(
2488 input_api.PresubmitLocalPath(),
2489 'tools', 'json_comment_eater')]
2490 import json_comment_eater
2491 return json_comment_eater
2492
2493
[email protected]99171a92014-06-03 08:44:472494def _GetJSONParseError(input_api, filename, eat_comments=True):
2495 try:
2496 contents = input_api.ReadFile(filename)
2497 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252498 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132499 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472500
2501 input_api.json.loads(contents)
2502 except ValueError as e:
2503 return e
2504 return None
2505
2506
2507def _GetIDLParseError(input_api, filename):
2508 try:
2509 contents = input_api.ReadFile(filename)
2510 idl_schema = input_api.os_path.join(
2511 input_api.PresubmitLocalPath(),
2512 'tools', 'json_schema_compiler', 'idl_schema.py')
2513 process = input_api.subprocess.Popen(
2514 [input_api.python_executable, idl_schema],
2515 stdin=input_api.subprocess.PIPE,
2516 stdout=input_api.subprocess.PIPE,
2517 stderr=input_api.subprocess.PIPE,
2518 universal_newlines=True)
2519 (_, error) = process.communicate(input=contents)
2520 return error or None
2521 except ValueError as e:
2522 return e
2523
2524
2525def _CheckParseErrors(input_api, output_api):
2526 """Check that IDL and JSON files do not contain syntax errors."""
2527 actions = {
2528 '.idl': _GetIDLParseError,
2529 '.json': _GetJSONParseError,
2530 }
[email protected]99171a92014-06-03 08:44:472531 # Most JSON files are preprocessed and support comments, but these do not.
2532 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042533 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472534 ]
2535 # Only run IDL checker on files in these directories.
2536 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042537 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2538 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472539 ]
2540
2541 def get_action(affected_file):
2542 filename = affected_file.LocalPath()
2543 return actions.get(input_api.os_path.splitext(filename)[1])
2544
[email protected]99171a92014-06-03 08:44:472545 def FilterFile(affected_file):
2546 action = get_action(affected_file)
2547 if not action:
2548 return False
2549 path = affected_file.LocalPath()
2550
Sean Kau46e29bc2017-08-28 16:31:162551 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472552 return False
2553
2554 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162555 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472556 return False
2557 return True
2558
2559 results = []
2560 for affected_file in input_api.AffectedFiles(
2561 file_filter=FilterFile, include_deletes=False):
2562 action = get_action(affected_file)
2563 kwargs = {}
2564 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162565 _MatchesFile(input_api, json_no_comments_patterns,
2566 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472567 kwargs['eat_comments'] = False
2568 parse_error = action(input_api,
2569 affected_file.AbsoluteLocalPath(),
2570 **kwargs)
2571 if parse_error:
2572 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2573 (affected_file.LocalPath(), parse_error)))
2574 return results
2575
2576
[email protected]760deea2013-12-10 19:33:492577def _CheckJavaStyle(input_api, output_api):
2578 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472579 import sys
[email protected]760deea2013-12-10 19:33:492580 original_sys_path = sys.path
2581 try:
2582 sys.path = sys.path + [input_api.os_path.join(
2583 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2584 import checkstyle
2585 finally:
2586 # Restore sys.path to what it was before.
2587 sys.path = original_sys_path
2588
2589 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092590 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512591 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492592
2593
Nate Fischerdfd9812e2019-07-18 22:03:002594def _CheckPythonDevilInit(input_api, output_api):
2595 """Checks to make sure devil is initialized correctly in python scripts."""
2596 script_common_initialize_pattern = input_api.re.compile(
2597 r'script_common\.InitializeEnvironment\(')
2598 devil_env_config_initialize = input_api.re.compile(
2599 r'devil_env\.config\.Initialize\(')
2600
2601 errors = []
2602
2603 sources = lambda affected_file: input_api.FilterSourceFile(
2604 affected_file,
2605 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2606 (r'^build[\\/]android[\\/]devil_chromium\.py',
2607 r'^third_party[\\/].*',)),
2608 white_list=[r'.*\.py$'])
2609
2610 for f in input_api.AffectedSourceFiles(sources):
2611 for line_num, line in f.ChangedContents():
2612 if (script_common_initialize_pattern.search(line) or
2613 devil_env_config_initialize.search(line)):
2614 errors.append("%s:%d" % (f.LocalPath(), line_num))
2615
2616 results = []
2617
2618 if errors:
2619 results.append(output_api.PresubmitError(
2620 'Devil initialization should always be done using '
2621 'devil_chromium.Initialize() in the chromium project, to use better '
2622 'defaults for dependencies (ex. up-to-date version of adb).',
2623 errors))
2624
2625 return results
2626
2627
Sean Kau46e29bc2017-08-28 16:31:162628def _MatchesFile(input_api, patterns, path):
2629 for pattern in patterns:
2630 if input_api.re.search(pattern, path):
2631 return True
2632 return False
2633
2634
Daniel Cheng7052cdf2017-11-21 19:23:292635def _GetOwnersFilesToCheckForIpcOwners(input_api):
2636 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172637
Daniel Cheng7052cdf2017-11-21 19:23:292638 Returns:
2639 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2640 contain to cover IPC-related files with noparent reviewer rules.
2641 """
2642 # Whether or not a file affects IPC is (mostly) determined by a simple list
2643 # of filename patterns.
dchenge07de812016-06-20 19:27:172644 file_patterns = [
palmerb19a0932017-01-24 04:00:312645 # Legacy IPC:
dchenge07de812016-06-20 19:27:172646 '*_messages.cc',
2647 '*_messages*.h',
2648 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312649 # Mojo IPC:
dchenge07de812016-06-20 19:27:172650 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472651 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172652 '*_struct_traits*.*',
2653 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312654 '*.typemap',
2655 # Android native IPC:
2656 '*.aidl',
2657 # Blink uses a different file naming convention:
2658 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472659 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172660 '*StructTraits*.*',
2661 '*TypeConverter*.*',
2662 ]
2663
scottmg7a6ed5ba2016-11-04 18:22:042664 # These third_party directories do not contain IPCs, but contain files
2665 # matching the above patterns, which trigger false positives.
2666 exclude_paths = [
2667 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232668 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062669 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292670 'third_party/win_build_output/*',
Clark DuVallfb37334c2019-09-03 18:32:172671 # These aidl files are just used to communicate between class loaders
2672 # running in the same process.
2673 'weblayer/browser/java/org/chromium/weblayer_private/aidl/*',
scottmg7a6ed5ba2016-11-04 18:22:042674 ]
2675
dchenge07de812016-06-20 19:27:172676 # Dictionary mapping an OWNERS file path to Patterns.
2677 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2678 # rules ) to a PatternEntry.
2679 # PatternEntry is a dictionary with two keys:
2680 # - 'files': the files that are matched by this pattern
2681 # - 'rules': the per-file rules needed for this pattern
2682 # For example, if we expect OWNERS file to contain rules for *.mojom and
2683 # *_struct_traits*.*, Patterns might look like this:
2684 # {
2685 # '*.mojom': {
2686 # 'files': ...,
2687 # 'rules': [
2688 # 'per-file *.mojom=set noparent',
2689 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2690 # ],
2691 # },
2692 # '*_struct_traits*.*': {
2693 # 'files': ...,
2694 # 'rules': [
2695 # 'per-file *_struct_traits*.*=set noparent',
2696 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2697 # ],
2698 # },
2699 # }
2700 to_check = {}
2701
Daniel Cheng13ca61a882017-08-25 15:11:252702 def AddPatternToCheck(input_file, pattern):
2703 owners_file = input_api.os_path.join(
2704 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2705 if owners_file not in to_check:
2706 to_check[owners_file] = {}
2707 if pattern not in to_check[owners_file]:
2708 to_check[owners_file][pattern] = {
2709 'files': [],
2710 'rules': [
2711 'per-file %s=set noparent' % pattern,
2712 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2713 ]
2714 }
Vaclav Brozekd5de76a2018-03-17 07:57:502715 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252716
dchenge07de812016-06-20 19:27:172717 # Iterate through the affected files to see what we actually need to check
2718 # for. We should only nag patch authors about per-file rules if a file in that
2719 # directory would match that pattern. If a directory only contains *.mojom
2720 # files and no *_messages*.h files, we should only nag about rules for
2721 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252722 for f in input_api.AffectedFiles(include_deletes=False):
2723 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362724 # affected files for .json, .cc, and .h files which look like they contain
2725 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162726 if (f.LocalPath().endswith('.json') and
2727 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2728 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252729 json_comment_eater = _ImportJSONCommentEater(input_api)
2730 mostly_json_lines = '\n'.join(f.NewContents())
2731 # Comments aren't allowed in strict JSON, so filter them out.
2732 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432733 try:
2734 json_content = input_api.json.loads(json_lines)
2735 except:
2736 # There's another PRESUBMIT check that already verifies that JSON files
2737 # are not invalid, so no need to emit another warning here.
2738 continue
Daniel Cheng13ca61a882017-08-25 15:11:252739 if 'interface_provider_specs' in json_content:
2740 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362741 else:
2742 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2743 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2744 if (manifest_pattern.search(f.LocalPath()) and not
2745 test_manifest_pattern.search(f.LocalPath())):
2746 # We expect all actual service manifest files to contain at least one
2747 # qualified reference to service_manager::Manifest.
2748 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2749 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172750 for pattern in file_patterns:
2751 if input_api.fnmatch.fnmatch(
2752 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042753 skip = False
2754 for exclude in exclude_paths:
2755 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2756 skip = True
2757 break
2758 if skip:
2759 continue
Daniel Cheng13ca61a882017-08-25 15:11:252760 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172761 break
2762
Daniel Cheng7052cdf2017-11-21 19:23:292763 return to_check
2764
2765
2766def _CheckIpcOwners(input_api, output_api):
2767 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2768 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2769
2770 if to_check:
2771 # If there are any OWNERS files to check, there are IPC-related changes in
2772 # this CL. Auto-CC the review list.
2773 output_api.AppendCC('[email protected]')
2774
2775 # Go through the OWNERS files to check, filtering out rules that are already
2776 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172777 for owners_file, patterns in to_check.iteritems():
2778 try:
2779 with file(owners_file) as f:
2780 lines = set(f.read().splitlines())
2781 for entry in patterns.itervalues():
2782 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2783 ]
2784 except IOError:
2785 # No OWNERS file, so all the rules are definitely missing.
2786 continue
2787
2788 # All the remaining lines weren't found in OWNERS files, so emit an error.
2789 errors = []
2790 for owners_file, patterns in to_check.iteritems():
2791 missing_lines = []
2792 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502793 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172794 missing_lines.extend(entry['rules'])
2795 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2796 if missing_lines:
2797 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052798 'Because of the presence of files:\n%s\n\n'
2799 '%s needs the following %d lines added:\n\n%s' %
2800 ('\n'.join(files), owners_file, len(missing_lines),
2801 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172802
2803 results = []
2804 if errors:
vabrf5ce3bf92016-07-11 14:52:412805 if input_api.is_committing:
2806 output = output_api.PresubmitError
2807 else:
2808 output = output_api.PresubmitPromptWarning
2809 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592810 'Found OWNERS files that need to be updated for IPC security ' +
2811 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172812 long_text='\n\n'.join(errors)))
2813
2814 return results
2815
2816
jbriance9e12f162016-11-25 07:57:502817def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312818 """Checks that added or removed lines in non third party affected
2819 header files do not lead to new useless class or struct forward
2820 declaration.
jbriance9e12f162016-11-25 07:57:502821 """
2822 results = []
2823 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2824 input_api.re.MULTILINE)
2825 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2826 input_api.re.MULTILINE)
2827 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312828 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192829 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492830 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312831 continue
2832
jbriance9e12f162016-11-25 07:57:502833 if not f.LocalPath().endswith('.h'):
2834 continue
2835
2836 contents = input_api.ReadFile(f)
2837 fwd_decls = input_api.re.findall(class_pattern, contents)
2838 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2839
2840 useless_fwd_decls = []
2841 for decl in fwd_decls:
2842 count = sum(1 for _ in input_api.re.finditer(
2843 r'\b%s\b' % input_api.re.escape(decl), contents))
2844 if count == 1:
2845 useless_fwd_decls.append(decl)
2846
2847 if not useless_fwd_decls:
2848 continue
2849
2850 for line in f.GenerateScmDiff().splitlines():
2851 if (line.startswith('-') and not line.startswith('--') or
2852 line.startswith('+') and not line.startswith('++')):
2853 for decl in useless_fwd_decls:
2854 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2855 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242856 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502857 (f.LocalPath(), decl)))
2858 useless_fwd_decls.remove(decl)
2859
2860 return results
2861
Jinsong Fan91ebbbd2019-04-16 14:57:172862def _CheckAndroidDebuggableBuild(input_api, output_api):
2863 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2864 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2865 this is a debuggable build of Android.
2866 """
2867 build_type_check_pattern = input_api.re.compile(
2868 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2869
2870 errors = []
2871
2872 sources = lambda affected_file: input_api.FilterSourceFile(
2873 affected_file,
2874 black_list=(_EXCLUDED_PATHS +
2875 _TEST_CODE_EXCLUDED_PATHS +
2876 input_api.DEFAULT_BLACK_LIST +
2877 (r"^android_webview[\\/]support_library[\\/]"
2878 "boundary_interfaces[\\/]",
2879 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2880 r'^third_party[\\/].*',
2881 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2882 r"webview[\\/]chromium[\\/]License.*",)),
2883 white_list=[r'.*\.java$'])
2884
2885 for f in input_api.AffectedSourceFiles(sources):
2886 for line_num, line in f.ChangedContents():
2887 if build_type_check_pattern.search(line):
2888 errors.append("%s:%d" % (f.LocalPath(), line_num))
2889
2890 results = []
2891
2892 if errors:
2893 results.append(output_api.PresubmitPromptWarning(
2894 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2895 ' Please use BuildInfo.isDebugAndroid() instead.',
2896 errors))
2897
2898 return results
jbriance9e12f162016-11-25 07:57:502899
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492900# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292901def _CheckAndroidToastUsage(input_api, output_api):
2902 """Checks that code uses org.chromium.ui.widget.Toast instead of
2903 android.widget.Toast (Chromium Toast doesn't force hardware
2904 acceleration on low-end devices, saving memory).
2905 """
2906 toast_import_pattern = input_api.re.compile(
2907 r'^import android\.widget\.Toast;$')
2908
2909 errors = []
2910
2911 sources = lambda affected_file: input_api.FilterSourceFile(
2912 affected_file,
2913 black_list=(_EXCLUDED_PATHS +
2914 _TEST_CODE_EXCLUDED_PATHS +
2915 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042916 (r'^chromecast[\\/].*',
2917 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492918 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292919
2920 for f in input_api.AffectedSourceFiles(sources):
2921 for line_num, line in f.ChangedContents():
2922 if toast_import_pattern.search(line):
2923 errors.append("%s:%d" % (f.LocalPath(), line_num))
2924
2925 results = []
2926
2927 if errors:
2928 results.append(output_api.PresubmitError(
2929 'android.widget.Toast usage is detected. Android toasts use hardware'
2930 ' acceleration, and can be\ncostly on low-end devices. Please use'
2931 ' org.chromium.ui.widget.Toast instead.\n'
2932 'Contact [email protected] if you have any questions.',
2933 errors))
2934
2935 return results
2936
2937
dgnaa68d5e2015-06-10 10:08:222938def _CheckAndroidCrLogUsage(input_api, output_api):
2939 """Checks that new logs using org.chromium.base.Log:
2940 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512941 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222942 """
pkotwicza1dd0b002016-05-16 14:41:042943
torne89540622017-03-24 19:41:302944 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042945 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302946 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042947 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302948 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042949 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2950 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092951 # The customtabs_benchmark is a small app that does not depend on Chromium
2952 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042953 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042954 ]
2955
dgnaa68d5e2015-06-10 10:08:222956 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122957 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2958 class_in_base_pattern = input_api.re.compile(
2959 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2960 has_some_log_import_pattern = input_api.re.compile(
2961 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222962 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122963 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222964 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512965 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222966 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222967
Vincent Scheib16d7b272015-09-15 18:09:072968 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222969 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492970 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042971 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122972
dgnaa68d5e2015-06-10 10:08:222973 tag_decl_errors = []
2974 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122975 tag_errors = []
dgn38736db2015-09-18 19:20:512976 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122977 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222978
2979 for f in input_api.AffectedSourceFiles(sources):
2980 file_content = input_api.ReadFile(f)
2981 has_modified_logs = False
2982
2983 # Per line checks
dgn87d9fb62015-06-12 09:15:122984 if (cr_log_import_pattern.search(file_content) or
2985 (class_in_base_pattern.search(file_content) and
2986 not has_some_log_import_pattern.search(file_content))):
2987 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222988 for line_num, line in f.ChangedContents():
2989
2990 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122991 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222992 if match:
2993 has_modified_logs = True
2994
2995 # Make sure it uses "TAG"
2996 if not match.group('tag') == 'TAG':
2997 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122998 else:
2999 # Report non cr Log function calls in changed lines
3000 for line_num, line in f.ChangedContents():
3001 if log_call_pattern.search(line):
3002 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223003
3004 # Per file checks
3005 if has_modified_logs:
3006 # Make sure the tag is using the "cr" prefix and is not too long
3007 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513008 tag_name = match.group('name') if match else None
3009 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223010 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513011 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223012 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513013 elif '.' in tag_name:
3014 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223015
3016 results = []
3017 if tag_decl_errors:
3018 results.append(output_api.PresubmitPromptWarning(
3019 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513020 '"private static final String TAG = "<package tag>".\n'
3021 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223022 tag_decl_errors))
3023
3024 if tag_length_errors:
3025 results.append(output_api.PresubmitError(
3026 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513027 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223028 tag_length_errors))
3029
3030 if tag_errors:
3031 results.append(output_api.PresubmitPromptWarning(
3032 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3033 tag_errors))
3034
dgn87d9fb62015-06-12 09:15:123035 if util_log_errors:
dgn4401aa52015-04-29 16:26:173036 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123037 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3038 util_log_errors))
3039
dgn38736db2015-09-18 19:20:513040 if tag_with_dot_errors:
3041 results.append(output_api.PresubmitPromptWarning(
3042 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3043 tag_with_dot_errors))
3044
dgn4401aa52015-04-29 16:26:173045 return results
3046
3047
Yoland Yanb92fa522017-08-28 17:37:063048def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3049 """Checks that junit.framework.* is no longer used."""
3050 deprecated_junit_framework_pattern = input_api.re.compile(
3051 r'^import junit\.framework\..*;',
3052 input_api.re.MULTILINE)
3053 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493054 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063055 errors = []
3056 for f in input_api.AffectedFiles(sources):
3057 for line_num, line in f.ChangedContents():
3058 if deprecated_junit_framework_pattern.search(line):
3059 errors.append("%s:%d" % (f.LocalPath(), line_num))
3060
3061 results = []
3062 if errors:
3063 results.append(output_api.PresubmitError(
3064 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3065 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3066 ' if you have any question.', errors))
3067 return results
3068
3069
3070def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3071 """Checks that if new Java test classes have inheritance.
3072 Either the new test class is JUnit3 test or it is a JUnit4 test class
3073 with a base class, either case is undesirable.
3074 """
3075 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3076
3077 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493078 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063079 errors = []
3080 for f in input_api.AffectedFiles(sources):
3081 if not f.OldContents():
3082 class_declaration_start_flag = False
3083 for line_num, line in f.ChangedContents():
3084 if class_declaration_pattern.search(line):
3085 class_declaration_start_flag = True
3086 if class_declaration_start_flag and ' extends ' in line:
3087 errors.append('%s:%d' % (f.LocalPath(), line_num))
3088 if '{' in line:
3089 class_declaration_start_flag = False
3090
3091 results = []
3092 if errors:
3093 results.append(output_api.PresubmitPromptWarning(
3094 'The newly created files include Test classes that inherits from base'
3095 ' class. Please do not use inheritance in JUnit4 tests or add new'
3096 ' JUnit3 tests. Contact [email protected] if you have any'
3097 ' questions.', errors))
3098 return results
3099
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203100
yolandyan45001472016-12-21 21:12:423101def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3102 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3103 deprecated_annotation_import_pattern = input_api.re.compile(
3104 r'^import android\.test\.suitebuilder\.annotation\..*;',
3105 input_api.re.MULTILINE)
3106 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493107 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423108 errors = []
3109 for f in input_api.AffectedFiles(sources):
3110 for line_num, line in f.ChangedContents():
3111 if deprecated_annotation_import_pattern.search(line):
3112 errors.append("%s:%d" % (f.LocalPath(), line_num))
3113
3114 results = []
3115 if errors:
3116 results.append(output_api.PresubmitError(
3117 'Annotations in android.test.suitebuilder.annotation have been'
3118 ' deprecated since API level 24. Please use android.support.test.filters'
3119 ' from //third_party/android_support_test_runner:runner_java instead.'
3120 ' Contact [email protected] if you have any questions.', errors))
3121 return results
3122
3123
agrieve7b6479d82015-10-07 14:24:223124def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3125 """Checks if MDPI assets are placed in a correct directory."""
3126 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3127 ('/res/drawable/' in f.LocalPath() or
3128 '/res/drawable-ldrtl/' in f.LocalPath()))
3129 errors = []
3130 for f in input_api.AffectedFiles(include_deletes=False,
3131 file_filter=file_filter):
3132 errors.append(' %s' % f.LocalPath())
3133
3134 results = []
3135 if errors:
3136 results.append(output_api.PresubmitError(
3137 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3138 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3139 '/res/drawable-ldrtl/.\n'
3140 'Contact [email protected] if you have questions.', errors))
3141 return results
3142
3143
Nate Fischer535972b2017-09-16 01:06:183144def _CheckAndroidWebkitImports(input_api, output_api):
3145 """Checks that code uses org.chromium.base.Callback instead of
3146 android.widget.ValueCallback except in the WebView glue layer.
3147 """
3148 valuecallback_import_pattern = input_api.re.compile(
3149 r'^import android\.webkit\.ValueCallback;$')
3150
3151 errors = []
3152
3153 sources = lambda affected_file: input_api.FilterSourceFile(
3154 affected_file,
3155 black_list=(_EXCLUDED_PATHS +
3156 _TEST_CODE_EXCLUDED_PATHS +
3157 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043158 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493159 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183160
3161 for f in input_api.AffectedSourceFiles(sources):
3162 for line_num, line in f.ChangedContents():
3163 if valuecallback_import_pattern.search(line):
3164 errors.append("%s:%d" % (f.LocalPath(), line_num))
3165
3166 results = []
3167
3168 if errors:
3169 results.append(output_api.PresubmitError(
3170 'android.webkit.ValueCallback usage is detected outside of the glue'
3171 ' layer. To stay compatible with the support library, android.webkit.*'
3172 ' classes should only be used inside the glue layer and'
3173 ' org.chromium.base.Callback should be used instead.',
3174 errors))
3175
3176 return results
3177
3178
Becky Zhou7c69b50992018-12-10 19:37:573179def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3180 """Checks Android XML styles """
3181 import sys
3182 original_sys_path = sys.path
3183 try:
3184 sys.path = sys.path + [input_api.os_path.join(
3185 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3186 import checkxmlstyle
3187 finally:
3188 # Restore sys.path to what it was before.
3189 sys.path = original_sys_path
3190
3191 if is_check_on_upload:
3192 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3193 else:
3194 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3195
3196
agrievef32bcc72016-04-04 14:57:403197class PydepsChecker(object):
3198 def __init__(self, input_api, pydeps_files):
3199 self._file_cache = {}
3200 self._input_api = input_api
3201 self._pydeps_files = pydeps_files
3202
3203 def _LoadFile(self, path):
3204 """Returns the list of paths within a .pydeps file relative to //."""
3205 if path not in self._file_cache:
3206 with open(path) as f:
3207 self._file_cache[path] = f.read()
3208 return self._file_cache[path]
3209
3210 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3211 """Returns an interable of paths within the .pydep, relativized to //."""
3212 os_path = self._input_api.os_path
3213 pydeps_dir = os_path.dirname(pydeps_path)
3214 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3215 if not l.startswith('*'))
3216 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3217
3218 def _CreateFilesToPydepsMap(self):
3219 """Returns a map of local_path -> list_of_pydeps."""
3220 ret = {}
3221 for pydep_local_path in self._pydeps_files:
3222 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3223 ret.setdefault(path, []).append(pydep_local_path)
3224 return ret
3225
3226 def ComputeAffectedPydeps(self):
3227 """Returns an iterable of .pydeps files that might need regenerating."""
3228 affected_pydeps = set()
3229 file_to_pydeps_map = None
3230 for f in self._input_api.AffectedFiles(include_deletes=True):
3231 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463232 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3233 # subrepositories. We can't figure out which files change, so re-check
3234 # all files.
3235 # Changes to print_python_deps.py affect all .pydeps.
3236 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403237 return self._pydeps_files
3238 elif local_path.endswith('.pydeps'):
3239 if local_path in self._pydeps_files:
3240 affected_pydeps.add(local_path)
3241 elif local_path.endswith('.py'):
3242 if file_to_pydeps_map is None:
3243 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3244 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3245 return affected_pydeps
3246
3247 def DetermineIfStale(self, pydeps_path):
3248 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413249 import difflib
John Budorick47ca3fe2018-02-10 00:53:103250 import os
3251
agrievef32bcc72016-04-04 14:57:403252 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3253 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103254 env = dict(os.environ)
3255 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403256 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103257 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413258 old_contents = old_pydeps_data[2:]
3259 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403260 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413261 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403262
3263
Tibor Goldschwendt360793f72019-06-25 18:23:493264def _ParseGclientArgs():
3265 args = {}
3266 with open('build/config/gclient_args.gni', 'r') as f:
3267 for line in f:
3268 line = line.strip()
3269 if not line or line.startswith('#'):
3270 continue
3271 attribute, value = line.split('=')
3272 args[attribute.strip()] = value.strip()
3273 return args
3274
3275
agrievef32bcc72016-04-04 14:57:403276def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3277 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403278 # This check is for Python dependency lists (.pydeps files), and involves
3279 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3280 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283281 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003282 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493283 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403284 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3285 results = []
3286 # First, check for new / deleted .pydeps.
3287 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033288 # Check whether we are running the presubmit check for a file in src.
3289 # f.LocalPath is relative to repo (src, or internal repo).
3290 # os_path.exists is relative to src repo.
3291 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3292 # to src and we can conclude that the pydeps is in src.
3293 if input_api.os_path.exists(f.LocalPath()):
3294 if f.LocalPath().endswith('.pydeps'):
3295 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3296 results.append(output_api.PresubmitError(
3297 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3298 'remove %s' % f.LocalPath()))
3299 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3300 results.append(output_api.PresubmitError(
3301 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3302 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403303
3304 if results:
3305 return results
3306
3307 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3308
3309 for pydep_path in checker.ComputeAffectedPydeps():
3310 try:
phajdan.jr0d9878552016-11-04 10:49:413311 result = checker.DetermineIfStale(pydep_path)
3312 if result:
3313 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403314 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413315 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3316 'To regenerate, run:\n\n %s' %
3317 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403318 except input_api.subprocess.CalledProcessError as error:
3319 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3320 long_text=error.output)]
3321
3322 return results
3323
3324
glidere61efad2015-02-18 17:39:433325def _CheckSingletonInHeaders(input_api, output_api):
3326 """Checks to make sure no header files have |Singleton<|."""
3327 def FileFilter(affected_file):
3328 # It's ok for base/memory/singleton.h to have |Singleton<|.
3329 black_list = (_EXCLUDED_PATHS +
3330 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043331 (r"^base[\\/]memory[\\/]singleton\.h$",
3332 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473333 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433334 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3335
sergeyu34d21222015-09-16 00:11:443336 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433337 files = []
3338 for f in input_api.AffectedSourceFiles(FileFilter):
3339 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3340 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3341 contents = input_api.ReadFile(f)
3342 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243343 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433344 pattern.search(line)):
3345 files.append(f)
3346 break
3347
3348 if files:
yolandyandaabc6d2016-04-18 18:29:393349 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443350 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433351 'Please move them to an appropriate source file so that the ' +
3352 'template gets instantiated in a single compilation unit.',
3353 files) ]
3354 return []
3355
3356
[email protected]fd20b902014-05-09 02:14:533357_DEPRECATED_CSS = [
3358 # Values
3359 ( "-webkit-box", "flex" ),
3360 ( "-webkit-inline-box", "inline-flex" ),
3361 ( "-webkit-flex", "flex" ),
3362 ( "-webkit-inline-flex", "inline-flex" ),
3363 ( "-webkit-min-content", "min-content" ),
3364 ( "-webkit-max-content", "max-content" ),
3365
3366 # Properties
3367 ( "-webkit-background-clip", "background-clip" ),
3368 ( "-webkit-background-origin", "background-origin" ),
3369 ( "-webkit-background-size", "background-size" ),
3370 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443371 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533372
3373 # Functions
3374 ( "-webkit-gradient", "gradient" ),
3375 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3376 ( "-webkit-linear-gradient", "linear-gradient" ),
3377 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3378 ( "-webkit-radial-gradient", "radial-gradient" ),
3379 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3380]
3381
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203382
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493383# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243384def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533385 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253386 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343387 documentation and iOS CSS for dom distiller
3388 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253389 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533390 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493391 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253392 black_list = (_EXCLUDED_PATHS +
3393 _TEST_CODE_EXCLUDED_PATHS +
3394 input_api.DEFAULT_BLACK_LIST +
3395 (r"^chrome/common/extensions/docs",
3396 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343397 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443398 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253399 r"^native_client_sdk"))
3400 file_filter = lambda f: input_api.FilterSourceFile(
3401 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533402 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3403 for line_num, line in fpath.ChangedContents():
3404 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023405 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533406 results.append(output_api.PresubmitError(
3407 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3408 (fpath.LocalPath(), line_num, deprecated_value, value)))
3409 return results
3410
mohan.reddyf21db962014-10-16 12:26:473411
rlanday6802cf632017-05-30 17:48:363412def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363413 bad_files = {}
3414 for f in input_api.AffectedFiles(include_deletes=False):
3415 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493416 not f.LocalPath().startswith('third_party/blink') and
3417 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363418 continue
3419
Daniel Bratell65b033262019-04-23 08:17:063420 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363421 continue
3422
Vaclav Brozekd5de76a2018-03-17 07:57:503423 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363424 if "#include" in line and "../" in line]
3425 if not relative_includes:
3426 continue
3427 bad_files[f.LocalPath()] = relative_includes
3428
3429 if not bad_files:
3430 return []
3431
3432 error_descriptions = []
3433 for file_path, bad_lines in bad_files.iteritems():
3434 error_description = file_path
3435 for line in bad_lines:
3436 error_description += '\n ' + line
3437 error_descriptions.append(error_description)
3438
3439 results = []
3440 results.append(output_api.PresubmitError(
3441 'You added one or more relative #include paths (including "../").\n'
3442 'These shouldn\'t be used because they can be used to include headers\n'
3443 'from code that\'s not correctly specified as a dependency in the\n'
3444 'relevant BUILD.gn file(s).',
3445 error_descriptions))
3446
3447 return results
3448
Takeshi Yoshinoe387aa32017-08-02 13:16:133449
Daniel Bratell65b033262019-04-23 08:17:063450def _CheckForCcIncludes(input_api, output_api):
3451 """Check that nobody tries to include a cc file. It's a relatively
3452 common error which results in duplicate symbols in object
3453 files. This may not always break the build until someone later gets
3454 very confusing linking errors."""
3455 results = []
3456 for f in input_api.AffectedFiles(include_deletes=False):
3457 # We let third_party code do whatever it wants
3458 if (f.LocalPath().startswith('third_party') and
3459 not f.LocalPath().startswith('third_party/blink') and
3460 not f.LocalPath().startswith('third_party\\blink')):
3461 continue
3462
3463 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3464 continue
3465
3466 for _, line in f.ChangedContents():
3467 if line.startswith('#include "'):
3468 included_file = line.split('"')[1]
3469 if _IsCPlusPlusFile(input_api, included_file):
3470 # The most common naming for external files with C++ code,
3471 # apart from standard headers, is to call them foo.inc, but
3472 # Chromium sometimes uses foo-inc.cc so allow that as well.
3473 if not included_file.endswith(('.h', '-inc.cc')):
3474 results.append(output_api.PresubmitError(
3475 'Only header files or .inc files should be included in other\n'
3476 'C++ files. Compiling the contents of a cc file more than once\n'
3477 'will cause duplicate information in the build which may later\n'
3478 'result in strange link_errors.\n' +
3479 f.LocalPath() + ':\n ' +
3480 line))
3481
3482 return results
3483
3484
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203485def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3486 if not isinstance(key, ast.Str):
3487 return 'Key at line %d must be a string literal' % key.lineno
3488 if not isinstance(value, ast.Dict):
3489 return 'Value at line %d must be a dict' % value.lineno
3490 if len(value.keys) != 1:
3491 return 'Dict at line %d must have single entry' % value.lineno
3492 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3493 return (
3494 'Entry at line %d must have a string literal \'filepath\' as key' %
3495 value.lineno)
3496 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133497
Takeshi Yoshinoe387aa32017-08-02 13:16:133498
Sergey Ulanov4af16052018-11-08 02:41:463499def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203500 if not isinstance(key, ast.Str):
3501 return 'Key at line %d must be a string literal' % key.lineno
3502 if not isinstance(value, ast.List):
3503 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463504 for element in value.elts:
3505 if not isinstance(element, ast.Str):
3506 return 'Watchlist elements on line %d is not a string' % key.lineno
3507 if not email_regex.match(element.s):
3508 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3509 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203510 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133511
Takeshi Yoshinoe387aa32017-08-02 13:16:133512
Sergey Ulanov4af16052018-11-08 02:41:463513def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203514 mismatch_template = (
3515 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3516 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133517
Sergey Ulanov4af16052018-11-08 02:41:463518 email_regex = input_api.re.compile(
3519 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3520
3521 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203522 i = 0
3523 last_key = ''
3524 while True:
3525 if i >= len(wd_dict.keys):
3526 if i >= len(w_dict.keys):
3527 return None
3528 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3529 elif i >= len(w_dict.keys):
3530 return (
3531 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133532
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203533 wd_key = wd_dict.keys[i]
3534 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133535
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203536 result = _CheckWatchlistDefinitionsEntrySyntax(
3537 wd_key, wd_dict.values[i], ast)
3538 if result is not None:
3539 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133540
Sergey Ulanov4af16052018-11-08 02:41:463541 result = _CheckWatchlistsEntrySyntax(
3542 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203543 if result is not None:
3544 return 'Bad entry in WATCHLISTS dict: %s' % result
3545
3546 if wd_key.s != w_key.s:
3547 return mismatch_template % (
3548 '%s at line %d' % (wd_key.s, wd_key.lineno),
3549 '%s at line %d' % (w_key.s, w_key.lineno))
3550
3551 if wd_key.s < last_key:
3552 return (
3553 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3554 (wd_key.lineno, w_key.lineno))
3555 last_key = wd_key.s
3556
3557 i = i + 1
3558
3559
Sergey Ulanov4af16052018-11-08 02:41:463560def _CheckWATCHLISTSSyntax(expression, input_api):
3561 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203562 if not isinstance(expression, ast.Expression):
3563 return 'WATCHLISTS file must contain a valid expression'
3564 dictionary = expression.body
3565 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3566 return 'WATCHLISTS file must have single dict with exactly two entries'
3567
3568 first_key = dictionary.keys[0]
3569 first_value = dictionary.values[0]
3570 second_key = dictionary.keys[1]
3571 second_value = dictionary.values[1]
3572
3573 if (not isinstance(first_key, ast.Str) or
3574 first_key.s != 'WATCHLIST_DEFINITIONS' or
3575 not isinstance(first_value, ast.Dict)):
3576 return (
3577 'The first entry of the dict in WATCHLISTS file must be '
3578 'WATCHLIST_DEFINITIONS dict')
3579
3580 if (not isinstance(second_key, ast.Str) or
3581 second_key.s != 'WATCHLISTS' or
3582 not isinstance(second_value, ast.Dict)):
3583 return (
3584 'The second entry of the dict in WATCHLISTS file must be '
3585 'WATCHLISTS dict')
3586
Sergey Ulanov4af16052018-11-08 02:41:463587 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133588
3589
3590def _CheckWATCHLISTS(input_api, output_api):
3591 for f in input_api.AffectedFiles(include_deletes=False):
3592 if f.LocalPath() == 'WATCHLISTS':
3593 contents = input_api.ReadFile(f, 'r')
3594
3595 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203596 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133597 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203598 # Get an AST tree for it and scan the tree for detailed style checking.
3599 expression = input_api.ast.parse(
3600 contents, filename='WATCHLISTS', mode='eval')
3601 except ValueError as e:
3602 return [output_api.PresubmitError(
3603 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3604 except SyntaxError as e:
3605 return [output_api.PresubmitError(
3606 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3607 except TypeError as e:
3608 return [output_api.PresubmitError(
3609 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133610
Sergey Ulanov4af16052018-11-08 02:41:463611 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203612 if result is not None:
3613 return [output_api.PresubmitError(result)]
3614 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133615
3616 return []
3617
3618
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193619def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3620 """Checks that newly added header files have corresponding GN changes.
3621 Note that this is only a heuristic. To be precise, run script:
3622 build/check_gn_headers.py.
3623 """
3624
3625 def headers(f):
3626 return input_api.FilterSourceFile(
3627 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3628
3629 new_headers = []
3630 for f in input_api.AffectedSourceFiles(headers):
3631 if f.Action() != 'A':
3632 continue
3633 new_headers.append(f.LocalPath())
3634
3635 def gn_files(f):
3636 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3637
3638 all_gn_changed_contents = ''
3639 for f in input_api.AffectedSourceFiles(gn_files):
3640 for _, line in f.ChangedContents():
3641 all_gn_changed_contents += line
3642
3643 problems = []
3644 for header in new_headers:
3645 basename = input_api.os_path.basename(header)
3646 if basename not in all_gn_changed_contents:
3647 problems.append(header)
3648
3649 if problems:
3650 return [output_api.PresubmitPromptWarning(
3651 'Missing GN changes for new header files', items=sorted(problems),
3652 long_text='Please double check whether newly added header files need '
3653 'corresponding changes in gn or gni files.\nThis checking is only a '
3654 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3655 'Read https://crbug.com/661774 for more info.')]
3656 return []
3657
3658
Michael Giuffridad3bc8672018-10-25 22:48:023659def _CheckCorrectProductNameInMessages(input_api, output_api):
3660 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3661
3662 This assumes we won't intentionally reference one product from the other
3663 product.
3664 """
3665 all_problems = []
3666 test_cases = [{
3667 "filename_postfix": "google_chrome_strings.grd",
3668 "correct_name": "Chrome",
3669 "incorrect_name": "Chromium",
3670 }, {
3671 "filename_postfix": "chromium_strings.grd",
3672 "correct_name": "Chromium",
3673 "incorrect_name": "Chrome",
3674 }]
3675
3676 for test_case in test_cases:
3677 problems = []
3678 filename_filter = lambda x: x.LocalPath().endswith(
3679 test_case["filename_postfix"])
3680
3681 # Check each new line. Can yield false positives in multiline comments, but
3682 # easier than trying to parse the XML because messages can have nested
3683 # children, and associating message elements with affected lines is hard.
3684 for f in input_api.AffectedSourceFiles(filename_filter):
3685 for line_num, line in f.ChangedContents():
3686 if "<message" in line or "<!--" in line or "-->" in line:
3687 continue
3688 if test_case["incorrect_name"] in line:
3689 problems.append(
3690 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3691
3692 if problems:
3693 message = (
3694 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3695 % (test_case["correct_name"], test_case["correct_name"],
3696 test_case["incorrect_name"]))
3697 all_problems.append(
3698 output_api.PresubmitPromptWarning(message, items=problems))
3699
3700 return all_problems
3701
3702
Dirk Pranke3c18a382019-03-15 01:07:513703def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3704 # TODO(crbug.com/941824): We need to make sure the entries in
3705 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3706 # so that users of //buildtools in other projects get the same tooling
3707 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3708 # support to gclient, we can eliminate the duplication and delete
3709 # this presubmit check.
3710
3711 # Update this regexp if new revisions are added to the files.
3712 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013713 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513714
3715 # If a user is changing one revision, they need to change the same
3716 # line in both files. This means that any given change should contain
3717 # exactly the same list of changed lines that match the regexps. The
3718 # replace(' ', '') call allows us to ignore whitespace changes to the
3719 # lines. The 'long_text' parameter to the error will contain the
3720 # list of changed lines in both files, which should make it easy enough
3721 # to spot the error without going overboard in this implementation.
3722 revs_changes = {
3723 'DEPS': {},
3724 'buildtools/DEPS': {},
3725 }
3726 long_text = ''
3727
3728 for f in input_api.AffectedFiles(
3729 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3730 for line_num, line in f.ChangedContents():
3731 if rev_regexp.search(line):
3732 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3733 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3734
3735 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3736 return [output_api.PresubmitError(
3737 'Change buildtools revisions in sync in both //DEPS and '
3738 '//buildtools/DEPS.', long_text=long_text + '\n')]
3739 else:
3740 return []
3741
3742
Daniel Bratell93eb6c62019-04-29 20:13:363743def _CheckForTooLargeFiles(input_api, output_api):
3744 """Avoid large files, especially binary files, in the repository since
3745 git doesn't scale well for those. They will be in everyone's repo
3746 clones forever, forever making Chromium slower to clone and work
3747 with."""
3748
3749 # Uploading files to cloud storage is not trivial so we don't want
3750 # to set the limit too low, but the upper limit for "normal" large
3751 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3752 # anything over 20 MB is exceptional.
3753 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3754
3755 too_large_files = []
3756 for f in input_api.AffectedFiles():
3757 # Check both added and modified files (but not deleted files).
3758 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383759 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363760 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3761 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3762
3763 if too_large_files:
3764 message = (
3765 'Do not commit large files to git since git scales badly for those.\n' +
3766 'Instead put the large files in cloud storage and use DEPS to\n' +
3767 'fetch them.\n' + '\n'.join(too_large_files)
3768 )
3769 return [output_api.PresubmitError(
3770 'Too large files found in commit', long_text=message + '\n')]
3771 else:
3772 return []
3773
Max Morozb47503b2019-08-08 21:03:273774
3775def _CheckFuzzTargets(input_api, output_api):
3776 """Checks specific for fuzz target sources."""
3777 EXPORTED_SYMBOLS = [
3778 'LLVMFuzzerInitialize',
3779 'LLVMFuzzerCustomMutator',
3780 'LLVMFuzzerCustomCrossOver',
3781 'LLVMFuzzerMutate',
3782 ]
3783
3784 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3785
3786 def FilterFile(affected_file):
3787 """Ignore libFuzzer source code."""
3788 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
3789 black_list = r"^third_party[\\/]libFuzzer"
3790
3791 return input_api.FilterSourceFile(
3792 affected_file,
3793 white_list=[white_list],
3794 black_list=[black_list])
3795
3796 files_with_missing_header = []
3797 for f in input_api.AffectedSourceFiles(FilterFile):
3798 contents = input_api.ReadFile(f, 'r')
3799 if REQUIRED_HEADER in contents:
3800 continue
3801
3802 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
3803 files_with_missing_header.append(f.LocalPath())
3804
3805 if not files_with_missing_header:
3806 return []
3807
3808 long_text = (
3809 'If you define any of the libFuzzer optional functions (%s), it is '
3810 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
3811 'work incorrectly on Mac (crbug.com/687076).\nNote that '
3812 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
3813 'to access command line arguments passed to the fuzzer. Instead, prefer '
3814 'static initialization and shared resources as documented in '
3815 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
3816 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
3817 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
3818 )
3819
3820 return [output_api.PresubmitPromptWarning(
3821 message="Missing '%s' in:" % REQUIRED_HEADER,
3822 items=files_with_missing_header,
3823 long_text=long_text)]
3824
3825
dgnaa68d5e2015-06-10 10:08:223826def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573827 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223828 results = []
dgnaa68d5e2015-06-10 10:08:223829 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173830 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223831 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293832 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063833 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3834 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423835 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183836 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573837 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3838 return results
3839
3840def _AndroidSpecificOnCommitChecks(input_api, output_api):
3841 """Groups commit checks that target android code."""
3842 results = []
3843 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223844 return results
3845
3846
[email protected]22c9bd72011-03-27 16:47:393847def _CommonChecks(input_api, output_api):
3848 """Checks common to both upload and commit."""
3849 results = []
3850 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383851 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543852 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083853
3854 author = input_api.change.author_email
3855 if author and author not in _KNOWN_ROBOTS:
3856 results.extend(
3857 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3858
[email protected]55459852011-08-10 15:17:193859 results.extend(
[email protected]760deea2013-12-10 19:33:493860 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233861 results.extend(
3862 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543863 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183864 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343865 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523866 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223867 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443868 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593869 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063870 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123871 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183872 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223873 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303874 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493875 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033876 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493877 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443878 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273879 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073880 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543881 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443882 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393883 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553884 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043885 results.extend(
3886 input_api.canned_checks.CheckChangeHasNoTabs(
3887 input_api,
3888 output_api,
3889 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403890 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163891 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083892 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243893 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473894 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043895 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053896 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143897 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233898 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433899 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403900 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153901 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173902 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503903 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363904 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063905 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133906 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433907 results.extend(input_api.RunTests(
3908 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143909 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023910 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513911 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:363912 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:003913 results.extend(_CheckPythonDevilInit(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243914
Vaclav Brozekcdc7defb2018-03-20 09:54:353915 for f in input_api.AffectedFiles():
3916 path, name = input_api.os_path.split(f.LocalPath())
3917 if name == 'PRESUBMIT.py':
3918 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003919 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3920 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073921 # The PRESUBMIT.py file (and the directory containing it) might
3922 # have been affected by being moved or removed, so only try to
3923 # run the tests if they still exist.
3924 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3925 input_api, output_api, full_path,
3926 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393927 return results
[email protected]1f7b4172010-01-28 01:17:343928
[email protected]b337cb5b2011-01-23 21:24:053929
[email protected]b8079ae4a2012-12-05 19:56:493930def _CheckPatchFiles(input_api, output_api):
3931 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3932 if f.LocalPath().endswith(('.orig', '.rej'))]
3933 if problems:
3934 return [output_api.PresubmitError(
3935 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033936 else:
3937 return []
[email protected]b8079ae4a2012-12-05 19:56:493938
3939
Kent Tamura5a8755d2017-06-29 23:37:073940def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213941 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3942 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3943 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073944 include_re = input_api.re.compile(
3945 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3946 extension_re = input_api.re.compile(r'\.[a-z]+$')
3947 errors = []
3948 for f in input_api.AffectedFiles():
3949 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3950 continue
3951 found_line_number = None
3952 found_macro = None
3953 for line_num, line in f.ChangedContents():
3954 match = macro_re.search(line)
3955 if match:
3956 found_line_number = line_num
3957 found_macro = match.group(2)
3958 break
3959 if not found_line_number:
3960 continue
3961
3962 found_include = False
3963 for line in f.NewContents():
3964 if include_re.search(line):
3965 found_include = True
3966 break
3967 if found_include:
3968 continue
3969
3970 if not f.LocalPath().endswith('.h'):
3971 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3972 try:
3973 content = input_api.ReadFile(primary_header_path, 'r')
3974 if include_re.search(content):
3975 continue
3976 except IOError:
3977 pass
3978 errors.append('%s:%d %s macro is used without including build/'
3979 'build_config.h.'
3980 % (f.LocalPath(), found_line_number, found_macro))
3981 if errors:
3982 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3983 return []
3984
3985
[email protected]b00342e7f2013-03-26 16:21:543986def _DidYouMeanOSMacro(bad_macro):
3987 try:
3988 return {'A': 'OS_ANDROID',
3989 'B': 'OS_BSD',
3990 'C': 'OS_CHROMEOS',
3991 'F': 'OS_FREEBSD',
3992 'L': 'OS_LINUX',
3993 'M': 'OS_MACOSX',
3994 'N': 'OS_NACL',
3995 'O': 'OS_OPENBSD',
3996 'P': 'OS_POSIX',
3997 'S': 'OS_SOLARIS',
3998 'W': 'OS_WIN'}[bad_macro[3].upper()]
3999 except KeyError:
4000 return ''
4001
4002
4003def _CheckForInvalidOSMacrosInFile(input_api, f):
4004 """Check for sensible looking, totally invalid OS macros."""
4005 preprocessor_statement = input_api.re.compile(r'^\s*#')
4006 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4007 results = []
4008 for lnum, line in f.ChangedContents():
4009 if preprocessor_statement.search(line):
4010 for match in os_macro.finditer(line):
4011 if not match.group(1) in _VALID_OS_MACROS:
4012 good = _DidYouMeanOSMacro(match.group(1))
4013 did_you_mean = ' (did you mean %s?)' % good if good else ''
4014 results.append(' %s:%d %s%s' % (f.LocalPath(),
4015 lnum,
4016 match.group(1),
4017 did_you_mean))
4018 return results
4019
4020
4021def _CheckForInvalidOSMacros(input_api, output_api):
4022 """Check all affected files for invalid OS macros."""
4023 bad_macros = []
tzik3f295992018-12-04 20:32:234024 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474025 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544026 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4027
4028 if not bad_macros:
4029 return []
4030
4031 return [output_api.PresubmitError(
4032 'Possibly invalid OS macro[s] found. Please fix your code\n'
4033 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4034
lliabraa35bab3932014-10-01 12:16:444035
4036def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4037 """Check all affected files for invalid "if defined" macros."""
4038 ALWAYS_DEFINED_MACROS = (
4039 "TARGET_CPU_PPC",
4040 "TARGET_CPU_PPC64",
4041 "TARGET_CPU_68K",
4042 "TARGET_CPU_X86",
4043 "TARGET_CPU_ARM",
4044 "TARGET_CPU_MIPS",
4045 "TARGET_CPU_SPARC",
4046 "TARGET_CPU_ALPHA",
4047 "TARGET_IPHONE_SIMULATOR",
4048 "TARGET_OS_EMBEDDED",
4049 "TARGET_OS_IPHONE",
4050 "TARGET_OS_MAC",
4051 "TARGET_OS_UNIX",
4052 "TARGET_OS_WIN32",
4053 )
4054 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4055 results = []
4056 for lnum, line in f.ChangedContents():
4057 for match in ifdef_macro.finditer(line):
4058 if match.group(1) in ALWAYS_DEFINED_MACROS:
4059 always_defined = ' %s is always defined. ' % match.group(1)
4060 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4061 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4062 lnum,
4063 always_defined,
4064 did_you_mean))
4065 return results
4066
4067
4068def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4069 """Check all affected files for invalid "if defined" macros."""
4070 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054071 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444072 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054073 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214074 continue
lliabraa35bab3932014-10-01 12:16:444075 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4076 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4077
4078 if not bad_macros:
4079 return []
4080
4081 return [output_api.PresubmitError(
4082 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4083 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4084 bad_macros)]
4085
4086
mlamouria82272622014-09-16 18:45:044087def _CheckForIPCRules(input_api, output_api):
4088 """Check for same IPC rules described in
4089 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4090 """
4091 base_pattern = r'IPC_ENUM_TRAITS\('
4092 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4093 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4094
4095 problems = []
4096 for f in input_api.AffectedSourceFiles(None):
4097 local_path = f.LocalPath()
4098 if not local_path.endswith('.h'):
4099 continue
4100 for line_number, line in f.ChangedContents():
4101 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4102 problems.append(
4103 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4104
4105 if problems:
4106 return [output_api.PresubmitPromptWarning(
4107 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4108 else:
4109 return []
4110
[email protected]b00342e7f2013-03-26 16:21:544111
Stephen Martinis97a394142018-06-07 23:06:054112def _CheckForLongPathnames(input_api, output_api):
4113 """Check to make sure no files being submitted have long paths.
4114 This causes issues on Windows.
4115 """
4116 problems = []
4117 for f in input_api.AffectedSourceFiles(None):
4118 local_path = f.LocalPath()
4119 # Windows has a path limit of 260 characters. Limit path length to 200 so
4120 # that we have some extra for the prefix on dev machines and the bots.
4121 if len(local_path) > 200:
4122 problems.append(local_path)
4123
4124 if problems:
4125 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4126 else:
4127 return []
4128
4129
Daniel Bratell8ba52722018-03-02 16:06:144130def _CheckForIncludeGuards(input_api, output_api):
4131 """Check that header files have proper guards against multiple inclusion.
4132 If a file should not have such guards (and it probably should) then it
4133 should include the string "no-include-guard-because-multiply-included".
4134 """
Daniel Bratell6a75baef62018-06-04 10:04:454135 def is_chromium_header_file(f):
4136 # We only check header files under the control of the Chromium
4137 # project. That is, those outside third_party apart from
4138 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324139 # We also exclude *_message_generator.h headers as they use
4140 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454141 file_with_path = input_api.os_path.normpath(f.LocalPath())
4142 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324143 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454144 (not file_with_path.startswith('third_party') or
4145 file_with_path.startswith(
4146 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144147
4148 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344149 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144150
4151 errors = []
4152
Daniel Bratell6a75baef62018-06-04 10:04:454153 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144154 guard_name = None
4155 guard_line_number = None
4156 seen_guard_end = False
4157
4158 file_with_path = input_api.os_path.normpath(f.LocalPath())
4159 base_file_name = input_api.os_path.splitext(
4160 input_api.os_path.basename(file_with_path))[0]
4161 upper_base_file_name = base_file_name.upper()
4162
4163 expected_guard = replace_special_with_underscore(
4164 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144165
4166 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574167 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4168 # are too many (1000+) files with slight deviations from the
4169 # coding style. The most important part is that the include guard
4170 # is there, and that it's unique, not the name so this check is
4171 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144172 #
4173 # As code becomes more uniform, this could be made stricter.
4174
4175 guard_name_pattern_list = [
4176 # Anything with the right suffix (maybe with an extra _).
4177 r'\w+_H__?',
4178
Daniel Bratell39b5b062018-05-16 18:09:574179 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144180 r'\w+_h',
4181
4182 # Anything including the uppercase name of the file.
4183 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4184 upper_base_file_name)) + r'\w*',
4185 ]
4186 guard_name_pattern = '|'.join(guard_name_pattern_list)
4187 guard_pattern = input_api.re.compile(
4188 r'#ifndef\s+(' + guard_name_pattern + ')')
4189
4190 for line_number, line in enumerate(f.NewContents()):
4191 if 'no-include-guard-because-multiply-included' in line:
4192 guard_name = 'DUMMY' # To not trigger check outside the loop.
4193 break
4194
4195 if guard_name is None:
4196 match = guard_pattern.match(line)
4197 if match:
4198 guard_name = match.group(1)
4199 guard_line_number = line_number
4200
Daniel Bratell39b5b062018-05-16 18:09:574201 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454202 # don't match the chromium style guide, but new files should
4203 # get it right.
4204 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574205 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144206 errors.append(output_api.PresubmitPromptWarning(
4207 'Header using the wrong include guard name %s' % guard_name,
4208 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:574209 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144210 else:
4211 # The line after #ifndef should have a #define of the same name.
4212 if line_number == guard_line_number + 1:
4213 expected_line = '#define %s' % guard_name
4214 if line != expected_line:
4215 errors.append(output_api.PresubmitPromptWarning(
4216 'Missing "%s" for include guard' % expected_line,
4217 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4218 'Expected: %r\nGot: %r' % (expected_line, line)))
4219
4220 if not seen_guard_end and line == '#endif // %s' % guard_name:
4221 seen_guard_end = True
4222 elif seen_guard_end:
4223 if line.strip() != '':
4224 errors.append(output_api.PresubmitPromptWarning(
4225 'Include guard %s not covering the whole file' % (
4226 guard_name), [f.LocalPath()]))
4227 break # Nothing else to check and enough to warn once.
4228
4229 if guard_name is None:
4230 errors.append(output_api.PresubmitPromptWarning(
4231 'Missing include guard %s' % expected_guard,
4232 [f.LocalPath()],
4233 'Missing include guard in %s\n'
4234 'Recommended name: %s\n'
4235 'This check can be disabled by having the string\n'
4236 'no-include-guard-because-multiply-included in the header.' %
4237 (f.LocalPath(), expected_guard)))
4238
4239 return errors
4240
4241
mostynbb639aca52015-01-07 20:31:234242def _CheckForWindowsLineEndings(input_api, output_api):
4243 """Check source code and known ascii text files for Windows style line
4244 endings.
4245 """
earthdok1b5e0ee2015-03-10 15:19:104246 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234247
4248 file_inclusion_pattern = (
4249 known_text_files,
4250 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4251 )
4252
mostynbb639aca52015-01-07 20:31:234253 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534254 source_file_filter = lambda f: input_api.FilterSourceFile(
4255 f, white_list=file_inclusion_pattern, black_list=None)
4256 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504257 include_file = False
4258 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234259 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504260 include_file = True
4261 if include_file:
4262 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234263
4264 if problems:
4265 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4266 'these files to contain Windows style line endings?\n' +
4267 '\n'.join(problems))]
4268
4269 return []
4270
4271
Vaclav Brozekd5de76a2018-03-17 07:57:504272def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134273 """Checks that all source files use SYSLOG properly."""
4274 syslog_files = []
4275 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564276 for line_number, line in f.ChangedContents():
4277 if 'SYSLOG' in line:
4278 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4279
pastarmovj89f7ee12016-09-20 14:58:134280 if syslog_files:
4281 return [output_api.PresubmitPromptWarning(
4282 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4283 ' calls.\nFiles to check:\n', items=syslog_files)]
4284 return []
4285
4286
[email protected]1f7b4172010-01-28 01:17:344287def CheckChangeOnUpload(input_api, output_api):
4288 results = []
4289 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474290 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284291 results.extend(
jam93a6ee792017-02-08 23:59:224292 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194293 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224294 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134295 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164296 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534297 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194298 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274299 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544300 return results
[email protected]ca8d1982009-02-19 16:33:124301
4302
[email protected]1bfb8322014-04-23 01:02:414303def GetTryServerMasterForBot(bot):
4304 """Returns the Try Server master for the given bot.
4305
[email protected]0bb112362014-07-26 04:38:324306 It tries to guess the master from the bot name, but may still fail
4307 and return None. There is no longer a default master.
4308 """
4309 # Potentially ambiguous bot names are listed explicitly.
4310 master_map = {
tandriie5587792016-07-14 00:34:504311 'chromium_presubmit': 'master.tryserver.chromium.linux',
4312 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414313 }
[email protected]0bb112362014-07-26 04:38:324314 master = master_map.get(bot)
4315 if not master:
wnwen4fbaab82016-05-25 12:54:364316 if 'android' in bot:
tandriie5587792016-07-14 00:34:504317 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364318 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504319 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324320 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504321 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324322 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504323 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324324 return master
[email protected]1bfb8322014-04-23 01:02:414325
4326
[email protected]ca8d1982009-02-19 16:33:124327def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544328 results = []
[email protected]1f7b4172010-01-28 01:17:344329 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574330 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544331 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274332 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344333 input_api,
4334 output_api,
[email protected]2fdd1f362013-01-16 03:56:034335 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274336
jam93a6ee792017-02-08 23:59:224337 results.extend(
4338 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544339 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4340 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414341 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4342 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544343 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144344
4345
4346def _CheckTranslationScreenshots(input_api, output_api):
4347 PART_FILE_TAG = "part"
4348 import os
4349 import sys
4350 from io import StringIO
4351
4352 try:
4353 old_sys_path = sys.path
4354 sys.path = sys.path + [input_api.os_path.join(
4355 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4356 import grit.grd_reader
4357 import grit.node.message
4358 import grit.util
4359 finally:
4360 sys.path = old_sys_path
4361
4362 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4363 """Load the grd file and return a dict of message ids to messages.
4364
4365 Ignores any nested grdp files pointed by <part> tag.
4366 """
4367 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4368 stop_after=None, first_ids_file=None,
Julian Pastarmov4f7af532019-07-17 19:25:374369 debug=False, defines={'_chromium': 1},
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144370 tags_to_ignore=set([PART_FILE_TAG]))
4371 return {
4372 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4373 grit.node.message.MessageNode)
4374 }
4375
4376 def _GetGrdpMessagesFromString(grdp_string):
4377 """Parses the contents of a grdp file given in grdp_string.
4378
4379 grd_reader can't parse grdp files directly. Instead, this creates a
4380 temporary directory with a grd file pointing to the grdp file, and loads the
4381 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4382 """
4383 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4384 <grit latest_public_release="1" current_release="1">
4385 <release seq="1">
4386 <messages>
4387 <part file="sub.grdp" />
4388 </messages>
4389 </release>
4390 </grit>
4391 """
4392 with grit.util.TempDir({'main.grd': WRAPPER,
4393 'sub.grdp': grdp_string}) as temp_dir:
4394 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4395
4396 new_or_added_paths = set(f.LocalPath()
4397 for f in input_api.AffectedFiles()
4398 if (f.Action() == 'A' or f.Action() == 'M'))
4399 removed_paths = set(f.LocalPath()
4400 for f in input_api.AffectedFiles(include_deletes=True)
4401 if f.Action() == 'D')
4402
4403 affected_grds = [f for f in input_api.AffectedFiles()
4404 if (f.LocalPath().endswith('.grd') or
4405 f.LocalPath().endswith('.grdp'))]
4406 affected_png_paths = [f.AbsoluteLocalPath()
4407 for f in input_api.AffectedFiles()
4408 if (f.LocalPath().endswith('.png'))]
4409
4410 # Check for screenshots. Developers can upload screenshots using
4411 # tools/translation/upload_screenshots.py which finds and uploads
4412 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4413 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4414 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4415 #
4416 # The logic here is as follows:
4417 #
4418 # - If the CL has a .png file under the screenshots directory for a grd
4419 # file, warn the developer. Actual images should never be checked into the
4420 # Chrome repo.
4421 #
4422 # - If the CL contains modified or new messages in grd files and doesn't
4423 # contain the corresponding .sha1 files, warn the developer to add images
4424 # and upload them via tools/translation/upload_screenshots.py.
4425 #
4426 # - If the CL contains modified or new messages in grd files and the
4427 # corresponding .sha1 files, everything looks good.
4428 #
4429 # - If the CL contains removed messages in grd files but the corresponding
4430 # .sha1 files aren't removed, warn the developer to remove them.
4431 unnecessary_screenshots = []
4432 missing_sha1 = []
4433 unnecessary_sha1_files = []
4434
4435
4436 def _CheckScreenshotAdded(screenshots_dir, message_id):
4437 sha1_path = input_api.os_path.join(
4438 screenshots_dir, message_id + '.png.sha1')
4439 if sha1_path not in new_or_added_paths:
4440 missing_sha1.append(sha1_path)
4441
4442
4443 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4444 sha1_path = input_api.os_path.join(
4445 screenshots_dir, message_id + '.png.sha1')
4446 if sha1_path not in removed_paths:
4447 unnecessary_sha1_files.append(sha1_path)
4448
4449
4450 for f in affected_grds:
4451 file_path = f.LocalPath()
4452 old_id_to_msg_map = {}
4453 new_id_to_msg_map = {}
4454 if file_path.endswith('.grdp'):
4455 if f.OldContents():
4456 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394457 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144458 if f.NewContents():
4459 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394460 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144461 else:
4462 if f.OldContents():
4463 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394464 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144465 if f.NewContents():
4466 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394467 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144468
4469 # Compute added, removed and modified message IDs.
4470 old_ids = set(old_id_to_msg_map)
4471 new_ids = set(new_id_to_msg_map)
4472 added_ids = new_ids - old_ids
4473 removed_ids = old_ids - new_ids
4474 modified_ids = set([])
4475 for key in old_ids.intersection(new_ids):
4476 if (old_id_to_msg_map[key].FormatXml()
4477 != new_id_to_msg_map[key].FormatXml()):
4478 modified_ids.add(key)
4479
4480 grd_name, ext = input_api.os_path.splitext(
4481 input_api.os_path.basename(file_path))
4482 screenshots_dir = input_api.os_path.join(
4483 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4484
4485 # Check the screenshot directory for .png files. Warn if there is any.
4486 for png_path in affected_png_paths:
4487 if png_path.startswith(screenshots_dir):
4488 unnecessary_screenshots.append(png_path)
4489
4490 for added_id in added_ids:
4491 _CheckScreenshotAdded(screenshots_dir, added_id)
4492
4493 for modified_id in modified_ids:
4494 _CheckScreenshotAdded(screenshots_dir, modified_id)
4495
4496 for removed_id in removed_ids:
4497 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4498
4499 results = []
4500 if unnecessary_screenshots:
4501 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394502 'Do not include actual screenshots in the changelist. Run '
4503 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144504 sorted(unnecessary_screenshots)))
4505
4506 if missing_sha1:
4507 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394508 'You are adding or modifying UI strings.\n'
4509 'To ensure the best translations, take screenshots of the relevant UI '
4510 '(https://g.co/chrome/translation) and add these files to your '
4511 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144512
4513 if unnecessary_sha1_files:
4514 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394515 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144516 sorted(unnecessary_sha1_files)))
4517
4518 return results