blob: 171164f6b4b864287a8c5e46bb8556c0c0b1dcdb [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-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]ca8d19842009-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[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d19842009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0447 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1851 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4452 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0453 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0554 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0455 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4756 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0457 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0858 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0459 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4460)
[email protected]ca8d19842009-02-19 16:33:1261
Daniel Bratell609102be2019-03-27 20:53:2162_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1563
[email protected]eea609a2011-11-18 13:10:1264_TEST_ONLY_WARNING = (
65 'You might be calling functions intended only for testing from\n'
66 'production code. It is OK to ignore this warning if you know what\n'
67 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5868 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1269
70
[email protected]cf9b78f2012-11-14 11:40:2871_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4072 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2173 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
74 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2875
wnwenbdc444e2016-05-25 13:44:1576
Daniel Bratell609102be2019-03-27 20:53:2177# Format: Sequence of tuples containing:
78# * String pattern or, if starting with a slash, a regular expression.
79# * Sequence of strings to show when the pattern matches.
80# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4181_BANNED_JAVA_FUNCTIONS = (
82 (
83 'StrictMode.allowThreadDiskReads()',
84 (
85 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
86 'directly.',
87 ),
88 False,
89 ),
90 (
91 'StrictMode.allowThreadDiskWrites()',
92 (
93 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
94 'directly.',
95 ),
96 False,
97 ),
98)
99
Daniel Bratell609102be2019-03-27 20:53:21100# Format: Sequence of tuples containing:
101# * String pattern or, if starting with a slash, a regular expression.
102# * Sequence of strings to show when the pattern matches.
103# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59104_BANNED_OBJC_FUNCTIONS = (
105 (
106 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20107 (
108 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59109 'prohibited. Please use CrTrackingArea instead.',
110 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
111 ),
112 False,
113 ),
114 (
[email protected]eaae1972014-04-16 04:17:26115 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20116 (
117 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59118 'instead.',
119 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
120 ),
121 False,
122 ),
123 (
124 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59127 'Please use |convertPoint:(point) fromView:nil| instead.',
128 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
129 ),
130 True,
131 ),
132 (
133 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20134 (
135 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59136 'Please use |convertPoint:(point) toView:nil| instead.',
137 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
138 ),
139 True,
140 ),
141 (
142 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20143 (
144 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59145 'Please use |convertRect:(point) fromView:nil| instead.',
146 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
147 ),
148 True,
149 ),
150 (
151 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20152 (
153 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59154 'Please use |convertRect:(point) toView:nil| instead.',
155 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
156 ),
157 True,
158 ),
159 (
160 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20161 (
162 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59163 'Please use |convertSize:(point) fromView:nil| instead.',
164 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
165 ),
166 True,
167 ),
168 (
169 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59172 'Please use |convertSize:(point) toView:nil| instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 True,
176 ),
jif65398702016-10-27 10:19:48177 (
178 r"/\s+UTF8String\s*]",
179 (
180 'The use of -[NSString UTF8String] is dangerous as it can return null',
181 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
182 'Please use |SysNSStringToUTF8| instead.',
183 ),
184 True,
185 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34186 (
187 r'__unsafe_unretained',
188 (
189 'The use of __unsafe_unretained is almost certainly wrong, unless',
190 'when interacting with NSFastEnumeration or NSInvocation.',
191 'Please use __weak in files build with ARC, nothing otherwise.',
192 ),
193 False,
194 ),
Avi Drissman7382afa02019-04-29 23:27:13195 (
196 'freeWhenDone:NO',
197 (
198 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
199 'Foundation types is prohibited.',
200 ),
201 True,
202 ),
[email protected]127f18ec2012-06-16 05:05:59203)
204
Daniel Bratell609102be2019-03-27 20:53:21205# Format: Sequence of tuples containing:
206# * String pattern or, if starting with a slash, a regular expression.
207# * Sequence of strings to show when the pattern matches.
208# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54209_BANNED_IOS_OBJC_FUNCTIONS = (
210 (
211 r'/\bTEST[(]',
212 (
213 'TEST() macro should not be used in Objective-C++ code as it does not ',
214 'drain the autorelease pool at the end of the test. Use TEST_F() ',
215 'macro instead with a fixture inheriting from PlatformTest (or a ',
216 'typedef).'
217 ),
218 True,
219 ),
220 (
221 r'/\btesting::Test\b',
222 (
223 'testing::Test should not be used in Objective-C++ code as it does ',
224 'not drain the autorelease pool at the end of the test. Use ',
225 'PlatformTest instead.'
226 ),
227 True,
228 ),
229)
230
danakj7a2b7082019-05-21 21:13:51231# Directories that contain deprecated Bind() or Callback types.
232# Find sub-directories from a given directory by running:
233# for i in `find . -maxdepth 1 -type d`; do
234# echo "-- $i"
235# (cd $i; git grep -P 'base::(Bind\(|(Callback<|Closure))'|wc -l)
236# done
237#
238# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
239# when they have been converted to modern callback types (OnceCallback,
240# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
241# checks for them and prevent regressions.
242_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
243 '^android_webview/browser/',
244 '^apps/',
245 '^ash/',
246 '^base/',
247 '^base/callback.h', # Intentional.
248 '^chrome/app/',
249 '^chrome/browser/',
250 '^chrome/chrome_elf/',
251 '^chrome/chrome_watcher/',
252 '^chrome/common/',
253 '^chrome/installer/',
254 '^chrome/notification_helper/',
255 '^chrome/renderer/',
256 '^chrome/services/',
257 '^chrome/test/',
258 '^chrome/tools/',
259 '^chrome/utility/',
260 '^chromecast/app/',
261 '^chromecast/browser/',
262 '^chromecast/crash/',
263 '^chromecast/media/',
264 '^chromecast/metrics/',
265 '^chromecast/net/',
266 '^chromeos/attestation/',
267 '^chromeos/audio/',
268 '^chromeos/components/',
269 '^chromeos/cryptohome/',
270 '^chromeos/dbus/',
271 '^chromeos/geolocation/',
272 '^chromeos/login/',
273 '^chromeos/network/',
274 '^chromeos/printing/',
275 '^chromeos/process_proxy/',
276 '^chromeos/services/',
277 '^chromeos/settings/',
278 '^chromeos/timezone/',
279 '^chromeos/tpm/',
280 '^components/arc/',
281 '^components/assist_ranker/',
282 '^components/autofill/',
283 '^components/autofill_assistant/',
284 '^components/bookmarks/',
285 '^components/browser_sync/',
286 '^components/browser_watcher/',
287 '^components/browsing_data/',
288 '^components/cast_channel/',
289 '^components/certificate_transparency/',
290 '^components/chromeos_camera/',
291 '^components/component_updater/',
292 '^components/content_settings/',
293 '^components/crash/',
294 '^components/cronet/',
295 '^components/data_reduction_proxy/',
296 '^components/discardable_memory/',
297 '^components/dom_distiller/',
298 '^components/domain_reliability/',
299 '^components/download/',
300 '^components/drive/',
301 '^components/exo/',
302 '^components/favicon/',
303 '^components/feature_engagement/',
304 '^components/feedback/',
305 '^components/flags_ui/',
306 '^components/gcm_driver/',
307 '^components/google/',
308 '^components/guest_view/',
309 '^components/heap_profiling/',
310 '^components/history/',
311 '^components/image_fetcher/',
312 '^components/invalidation/',
313 '^components/keyed_service/',
314 '^components/login/',
315 '^components/metrics/',
316 '^components/metrics_services_manager/',
317 '^components/nacl/',
318 '^components/navigation_interception/',
319 '^components/net_log/',
320 '^components/network_time/',
321 '^components/ntp_snippets/',
322 '^components/ntp_tiles/',
323 '^components/offline_items_collection/',
324 '^components/offline_pages/',
325 '^components/omnibox/',
326 '^components/ownership/',
327 '^components/pairing/',
328 '^components/password_manager/',
329 '^components/payments/',
330 '^components/plugins/',
331 '^components/policy/',
332 '^components/pref_registry/',
333 '^components/prefs/',
334 '^components/printing/',
335 '^components/proxy_config/',
336 '^components/quirks/',
337 '^components/rappor/',
338 '^components/remote_cocoa/',
339 '^components/renderer_context_menu/',
340 '^components/rlz/',
341 '^components/safe_browsing/',
342 '^components/search_engines/',
343 '^components/search_provider_logos/',
344 '^components/security_interstitials/',
345 '^components/security_state/',
346 '^components/services/',
347 '^components/sessions/',
348 '^components/signin/',
349 '^components/ssl_errors/',
350 '^components/storage_monitor/',
351 '^components/subresource_filter/',
352 '^components/suggestions/',
353 '^components/supervised_user_error_page/',
354 '^components/sync/',
355 '^components/sync_bookmarks/',
356 '^components/sync_device_info/',
357 '^components/sync_preferences/',
358 '^components/sync_sessions/',
359 '^components/test/',
360 '^components/tracing/',
361 '^components/translate/',
362 '^components/ukm/',
363 '^components/update_client/',
364 '^components/upload_list/',
365 '^components/variations/',
366 '^components/visitedlink/',
367 '^components/web_cache/',
368 '^components/web_resource/',
danakj7a2b7082019-05-21 21:13:51369 '^components/webcrypto/',
370 '^components/webdata/',
371 '^components/webdata_services/',
372 '^components/wifi/',
373 '^components/zoom/',
374 '^content/app/',
375 '^content/browser/',
376 '^content/child/',
377 '^content/common/',
378 '^content/public/',
379 '^content/renderer/android/',
380 '^content/renderer/fetchers/',
381 '^content/renderer/image_downloader/',
382 '^content/renderer/input/',
383 '^content/renderer/java/',
384 '^content/renderer/media/',
385 '^content/renderer/media_capture_from_element/',
386 '^content/renderer/media_recorder/',
387 '^content/renderer/p2p/',
388 '^content/renderer/pepper/',
389 '^content/renderer/service_worker/',
390 '^content/renderer/worker/',
391 '^content/test/',
392 '^content/utility/',
393 '^dbus/',
394 '^device/base/',
395 '^device/bluetooth/',
396 '^device/fido/',
397 '^device/gamepad/',
398 '^device/udev_linux/',
399 '^device/vr/',
400 '^extensions/',
401 '^gin/',
402 '^google_apis/dive/',
403 '^google_apis/gaia/',
404 '^google_apis/gcm/',
405 '^headless/',
406 '^ios/chrome/',
407 '^ios/components/',
408 '^ios/net/',
409 '^ios/web/',
410 '^ios/web_view/',
411 '^ipc/',
412 '^media/audio/',
413 '^media/base/',
414 '^media/capture/',
415 '^media/cast/',
416 '^media/cdm/',
417 '^media/device_monitors/',
418 '^media/ffmpeg/',
419 '^media/filters/',
420 '^media/formats/',
421 '^media/gpu/',
422 '^media/mojo/',
423 '^media/muxers/',
424 '^media/remoting/',
425 '^media/renderers/',
426 '^media/test/',
427 '^mojo/core/',
428 '^mojo/public/',
429 '^net/',
430 '^ppapi/proxy/',
431 '^ppapi/shared_impl/',
432 '^ppapi/tests/',
433 '^ppapi/thunk/',
434 '^remoting/base/',
435 '^remoting/client/',
436 '^remoting/codec/',
437 '^remoting/host/',
438 '^remoting/internal/',
439 '^remoting/ios/',
440 '^remoting/protocol/',
441 '^remoting/signaling/',
442 '^remoting/test/',
443 '^sandbox/linux/',
444 '^sandbox/win/',
445 '^services/',
446 '^storage/browser/',
447 '^testing/gmock_mutant.h',
448 '^testing/libfuzzer/',
449 '^third_party/blink/',
450 '^third_party/crashpad/crashpad/test/gtest_main.cc',
451 '^third_party/leveldatabase/leveldb_chrome.cc',
452 '^third_party/boringssl/gtest_main_chromium.cc',
453 '^third_party/cacheinvalidation/overrides/' +
454 'google/cacheinvalidation/deps/callback.h',
455 '^third_party/libaddressinput/chromium/chrome_address_validator.cc',
456 '^third_party/zlib/google/',
457 '^tools/android/',
458 '^tools/clang/base_bind_rewriters/', # Intentional.
459 '^tools/gdb/gdb_chrome.py', # Intentional.
460 '^ui/accelerated_widget_mac/',
461 '^ui/android/',
462 '^ui/aura/',
463 '^ui/base/',
464 '^ui/compositor/',
465 '^ui/display/',
466 '^ui/events/',
467 '^ui/gfx/',
468 '^ui/message_center/',
danakj7a2b7082019-05-21 21:13:51469 '^ui/snapshot/',
470 '^ui/views_content_client/',
471 '^ui/wm/',
472))
[email protected]127f18ec2012-06-16 05:05:59473
Daniel Bratell609102be2019-03-27 20:53:21474# Format: Sequence of tuples containing:
475# * String pattern or, if starting with a slash, a regular expression.
476# * Sequence of strings to show when the pattern matches.
477# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
478# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59479_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20480 (
thomasandersone7caaa9b2017-03-29 19:22:53481 r'\bNULL\b',
482 (
483 'New code should not use NULL. Use nullptr instead.',
484 ),
485 True,
486 (),
487 ),
Antonio Gomes07300d02019-03-13 20:59:57488 # Make sure that gtest's FRIEND_TEST() macro is not used; the
489 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
490 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53491 (
[email protected]23e6cbc2012-06-16 18:51:20492 'FRIEND_TEST(',
493 (
[email protected]e3c945502012-06-26 20:01:49494 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20495 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
496 ),
497 False,
[email protected]7345da02012-11-27 14:31:49498 (),
[email protected]23e6cbc2012-06-16 18:51:20499 ),
500 (
thomasanderson4b569052016-09-14 20:15:53501 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
502 (
503 'Chrome clients wishing to select events on X windows should use',
504 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
505 'you are selecting events from the GPU process, or if you are using',
506 'an XDisplay other than gfx::GetXDisplay().',
507 ),
508 True,
509 (
Egor Paskoce145c42018-09-28 19:31:04510 r"^ui[\\/]gl[\\/].*\.cc$",
511 r"^media[\\/]gpu[\\/].*\.cc$",
512 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53513 ),
514 ),
515 (
thomasandersone043e3ce2017-06-08 00:43:20516 r'XInternAtom|xcb_intern_atom',
517 (
thomasanderson11aa41d2017-06-08 22:22:38518 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20519 ),
520 True,
521 (
Egor Paskoce145c42018-09-28 19:31:04522 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
523 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
524 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20525 ),
526 ),
527 (
tomhudsone2c14d552016-05-26 17:07:46528 'setMatrixClip',
529 (
530 'Overriding setMatrixClip() is prohibited; ',
531 'the base function is deprecated. ',
532 ),
533 True,
534 (),
535 ),
536 (
[email protected]52657f62013-05-20 05:30:31537 'SkRefPtr',
538 (
539 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22540 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31541 ),
542 True,
543 (),
544 ),
545 (
546 'SkAutoRef',
547 (
548 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22549 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31550 ),
551 True,
552 (),
553 ),
554 (
555 'SkAutoTUnref',
556 (
557 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22558 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31559 ),
560 True,
561 (),
562 ),
563 (
564 'SkAutoUnref',
565 (
566 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
567 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22568 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31569 ),
570 True,
571 (),
572 ),
[email protected]d89eec82013-12-03 14:10:59573 (
574 r'/HANDLE_EINTR\(.*close',
575 (
576 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
577 'descriptor will be closed, and it is incorrect to retry the close.',
578 'Either call close directly and ignore its return value, or wrap close',
579 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
580 ),
581 True,
582 (),
583 ),
584 (
585 r'/IGNORE_EINTR\((?!.*close)',
586 (
587 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
588 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
589 ),
590 True,
591 (
592 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04593 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
594 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59595 ),
596 ),
[email protected]ec5b3f02014-04-04 18:43:43597 (
598 r'/v8::Extension\(',
599 (
600 'Do not introduce new v8::Extensions into the code base, use',
601 'gin::Wrappable instead. See http://crbug.com/334679',
602 ),
603 True,
[email protected]f55c90ee62014-04-12 00:50:03604 (
Egor Paskoce145c42018-09-28 19:31:04605 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03606 ),
[email protected]ec5b3f02014-04-04 18:43:43607 ),
skyostilf9469f72015-04-20 10:38:52608 (
jame2d1a952016-04-02 00:27:10609 '#pragma comment(lib,',
610 (
611 'Specify libraries to link with in build files and not in the source.',
612 ),
613 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41614 (
tzik3f295992018-12-04 20:32:23615 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04616 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41617 ),
jame2d1a952016-04-02 00:27:10618 ),
fdorayc4ac18d2017-05-01 21:39:59619 (
Gabriel Charette7cc6c432018-04-25 20:52:02620 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59621 (
622 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
623 ),
624 False,
625 (),
626 ),
627 (
Gabriel Charette7cc6c432018-04-25 20:52:02628 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59629 (
630 'Consider using THREAD_CHECKER macros instead of the class directly.',
631 ),
632 False,
633 (),
634 ),
dbeamb6f4fde2017-06-15 04:03:06635 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06636 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
637 (
638 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
639 'deprecated (http://crbug.com/634507). Please avoid converting away',
640 'from the Time types in Chromium code, especially if any math is',
641 'being done on time values. For interfacing with platform/library',
642 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
643 'type converter methods instead. For faking TimeXXX values (for unit',
644 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
645 'other use cases, please contact base/time/OWNERS.',
646 ),
647 False,
648 (),
649 ),
650 (
dbeamb6f4fde2017-06-15 04:03:06651 'CallJavascriptFunctionUnsafe',
652 (
653 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
654 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
655 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
656 ),
657 False,
658 (
Egor Paskoce145c42018-09-28 19:31:04659 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
660 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
661 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06662 ),
663 ),
dskiba1474c2bfd62017-07-20 02:19:24664 (
665 'leveldb::DB::Open',
666 (
667 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
668 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
669 "Chrome's tracing, making their memory usage visible.",
670 ),
671 True,
672 (
673 r'^third_party/leveldatabase/.*\.(cc|h)$',
674 ),
Gabriel Charette0592c3a2017-07-26 12:02:04675 ),
676 (
Chris Mumfordc38afb62017-10-09 17:55:08677 'leveldb::NewMemEnv',
678 (
679 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58680 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
681 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08682 ),
683 True,
684 (
685 r'^third_party/leveldatabase/.*\.(cc|h)$',
686 ),
687 ),
688 (
Gabriel Charetted9839bc2017-07-29 14:17:47689 'RunLoop::QuitCurrent',
690 (
Robert Liao64b7ab22017-08-04 23:03:43691 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
692 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47693 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41694 False,
Gabriel Charetted9839bc2017-07-29 14:17:47695 (),
Gabriel Charettea44975052017-08-21 23:14:04696 ),
697 (
698 'base::ScopedMockTimeMessageLoopTaskRunner',
699 (
Gabriel Charette87cc1af2018-04-25 20:52:51700 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
701 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
702 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
703 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
704 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04705 ),
Gabriel Charette87cc1af2018-04-25 20:52:51706 False,
Gabriel Charettea44975052017-08-21 23:14:04707 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57708 ),
709 (
710 r'std::regex',
711 (
712 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02713 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57714 ),
715 True,
716 (),
Francois Doray43670e32017-09-27 12:40:38717 ),
718 (
Peter Kasting991618a62019-06-17 22:00:09719 r'/\bstd::stoi\b',
720 (
721 'std::stoi uses exceptions to communicate results. ',
722 'Use base::StringToInt() instead.',
723 ),
724 True,
725 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
726 ),
727 (
728 r'/\bstd::stol\b',
729 (
730 'std::stol uses exceptions to communicate results. ',
731 'Use base::StringToInt() instead.',
732 ),
733 True,
734 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
735 ),
736 (
737 r'/\bstd::stoul\b',
738 (
739 'std::stoul uses exceptions to communicate results. ',
740 'Use base::StringToUint() instead.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
746 r'/\bstd::stoll\b',
747 (
748 'std::stoll uses exceptions to communicate results. ',
749 'Use base::StringToInt64() instead.',
750 ),
751 True,
752 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
753 ),
754 (
755 r'/\bstd::stoull\b',
756 (
757 'std::stoull uses exceptions to communicate results. ',
758 'Use base::StringToUint64() instead.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
762 ),
763 (
764 r'/\bstd::stof\b',
765 (
766 'std::stof uses exceptions to communicate results. ',
767 'For locale-independent values, e.g. reading numbers from disk',
768 'profiles, use base::StringToDouble().',
769 'For user-visible values, parse using ICU.',
770 ),
771 True,
772 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
773 ),
774 (
775 r'/\bstd::stod\b',
776 (
777 'std::stod uses exceptions to communicate results. ',
778 'For locale-independent values, e.g. reading numbers from disk',
779 'profiles, use base::StringToDouble().',
780 'For user-visible values, parse using ICU.',
781 ),
782 True,
783 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
784 ),
785 (
786 r'/\bstd::stold\b',
787 (
788 'std::stold uses exceptions to communicate results. ',
789 'For locale-independent values, e.g. reading numbers from disk',
790 'profiles, use base::StringToDouble().',
791 'For user-visible values, parse using ICU.',
792 ),
793 True,
794 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
795 ),
796 (
Daniel Bratell69334cc2019-03-26 11:07:45797 r'/\bstd::to_string\b',
798 (
799 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09800 'For locale-independent strings, e.g. writing numbers to disk',
801 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45802 'For user-visible strings, use base::FormatNumber() and',
803 'the related functions in base/i18n/number_formatting.h.',
804 ),
Peter Kasting991618a62019-06-17 22:00:09805 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21806 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45807 ),
808 (
809 r'/\bstd::shared_ptr\b',
810 (
811 'std::shared_ptr should not be used. Use scoped_refptr instead.',
812 ),
813 True,
Daniel Bratell609102be2019-03-27 20:53:21814 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
815 ),
816 (
Peter Kasting991618a62019-06-17 22:00:09817 r'/\bstd::weak_ptr\b',
818 (
819 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
820 ),
821 True,
822 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
823 ),
824 (
Daniel Bratell609102be2019-03-27 20:53:21825 r'/\blong long\b',
826 (
827 'long long is banned. Use stdint.h if you need a 64 bit number.',
828 ),
829 False, # Only a warning since it is already used.
830 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
831 ),
832 (
833 r'/\bstd::bind\b',
834 (
835 'std::bind is banned because of lifetime risks.',
836 'Use base::BindOnce or base::BindRepeating instead.',
837 ),
838 True,
839 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
840 ),
841 (
842 r'/\b#include <chrono>\b',
843 (
844 '<chrono> overlaps with Time APIs in base. Keep using',
845 'base classes.',
846 ),
847 True,
848 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
849 ),
850 (
851 r'/\b#include <exception>\b',
852 (
853 'Exceptions are banned and disabled in Chromium.',
854 ),
855 True,
856 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
857 ),
858 (
859 r'/\bstd::function\b',
860 (
861 'std::function is banned. Instead use base::Callback which directly',
862 'supports Chromium\'s weak pointers, ref counting and more.',
863 ),
Peter Kasting991618a62019-06-17 22:00:09864 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21865 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
866 ),
867 (
868 r'/\b#include <random>\b',
869 (
870 'Do not use any random number engines from <random>. Instead',
871 'use base::RandomBitGenerator.',
872 ),
873 True,
874 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
875 ),
876 (
877 r'/\bstd::ratio\b',
878 (
879 'std::ratio is banned by the Google Style Guide.',
880 ),
881 True,
882 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45883 ),
884 (
Francois Doray43670e32017-09-27 12:40:38885 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
886 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
887 (
888 'Use the new API in base/threading/thread_restrictions.h.',
889 ),
Gabriel Charette04b138f2018-08-06 00:03:22890 False,
Francois Doray43670e32017-09-27 12:40:38891 (),
892 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38893 (
danakj7a2b7082019-05-21 21:13:51894 r'/\bbase::Bind\(',
895 (
896 'Please use base::Bind{Once,Repeating} instead',
897 'of base::Bind. (crbug.com/714018)',
898 ),
899 False,
900 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
901 ),
902 (
903 r'/\bbase::Callback[<:]',
904 (
905 'Please use base::{Once,Repeating}Callback instead',
906 'of base::Callback. (crbug.com/714018)',
907 ),
908 False,
909 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
910 ),
911 (
912 r'/\bbase::Closure\b',
913 (
914 'Please use base::{Once,Repeating}Closure instead',
915 'of base::Closure. (crbug.com/714018)',
916 ),
917 False,
918 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
919 ),
920 (
Alex Ilin5929abe32019-04-03 17:09:34921 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45922 (
923 'base::SharedMemory is deprecated. Please use',
924 '{Writable,ReadOnly}SharedMemoryRegion instead.',
925 ),
926 False,
927 (),
928 ),
929 (
Michael Giuffrida7f93d6922019-04-19 14:39:58930 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19931 (
932 'RunMessageLoop is deprecated, use RunLoop instead.',
933 ),
934 False,
935 (),
936 ),
937 (
938 r'RunThisRunLoop',
939 (
940 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
941 ),
942 False,
943 (),
944 ),
945 (
946 r'RunAllPendingInMessageLoop()',
947 (
948 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
949 "if you're convinced you need this.",
950 ),
951 False,
952 (),
953 ),
954 (
955 r'RunAllPendingInMessageLoop(BrowserThread',
956 (
957 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
958 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
959 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
960 'async events instead of flushing threads.',
961 ),
962 False,
963 (),
964 ),
965 (
966 r'MessageLoopRunner',
967 (
968 'MessageLoopRunner is deprecated, use RunLoop instead.',
969 ),
970 False,
971 (),
972 ),
973 (
974 r'GetDeferredQuitTaskForRunLoop',
975 (
976 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
977 "gab@ if you found a use case where this is the only solution.",
978 ),
979 False,
980 (),
981 ),
982 (
Victor Costane48a2e82019-03-15 22:02:34983 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16984 (
Victor Costane48a2e82019-03-15 22:02:34985 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16986 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
987 ),
988 True,
989 (
990 r'^sql/initialization\.(cc|h)$',
991 r'^third_party/sqlite/.*\.(c|cc|h)$',
992 ),
993 ),
Matt Menke7f520a82018-03-28 21:38:37994 (
995 'net::URLFetcher',
996 (
997 'net::URLFetcher should no longer be used in content embedders. ',
998 'Instead, use network::SimpleURLLoader instead, which supports ',
999 'an out-of-process network stack. ',
1000 'net::URLFetcher may still be used in binaries that do not embed',
1001 'content.',
1002 ),
Matt Menke59716d02018-04-05 12:45:531003 False,
Matt Menke7f520a82018-03-28 21:38:371004 (
Egor Paskoce145c42018-09-28 19:31:041005 r'^ios[\\/].*\.(cc|h)$',
1006 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:371007 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:041008 r'^net[\\/].*\.(cc|h)$',
1009 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Fabrice de Gans-Riberia16cac82019-06-03 19:03:201010 r'^fuchsia/engine/web_engine_debug_integration_test\.cc$',
Matt Menke7f520a82018-03-28 21:38:371011 ),
1012 ),
jdoerried7d10ab2018-04-27 10:46:131013 (
tzik5de2157f2018-05-08 03:42:471014 r'std::random_shuffle',
1015 (
1016 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1017 'base::RandomShuffle instead.'
1018 ),
1019 True,
1020 (),
1021 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241022 (
1023 'ios/web/public/test/http_server',
1024 (
1025 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1026 ),
1027 False,
1028 (),
1029 ),
Robert Liao764c9492019-01-24 18:46:281030 (
1031 'GetAddressOf',
1032 (
1033 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1034 'implicated in a few leaks. Use operator& instead.'
1035 ),
1036 True,
1037 (),
1038 ),
Antonio Gomes07300d02019-03-13 20:59:571039 (
1040 'DEFINE_TYPE_CASTS',
1041 (
1042 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
1043 '//third_party/blink/renderer/platform/casting.h.'
1044 ),
1045 True,
1046 (
1047 r'^third_party/blink/renderer/.*\.(cc|h)$',
1048 ),
1049 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381050 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371051 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381052 (
1053 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1054 ),
1055 True,
1056 (),
1057 ),
Ben Lewisa9514602019-04-29 17:53:051058 (
1059 'SHFileOperation',
1060 (
1061 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1062 'complex functions to achieve the same goals. Use IFileOperation for ',
1063 'any esoteric actions instead.'
1064 ),
1065 True,
1066 (),
1067 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181068 (
Cliff Smolinsky81951642019-04-30 21:39:511069 'StringFromGUID2',
1070 (
1071 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1072 'Use base::win::String16FromGUID instead.'
1073 ),
1074 True,
1075 (
1076 r'/base/win/win_util_unittest.cc'
1077 ),
1078 ),
1079 (
1080 'StringFromCLSID',
1081 (
1082 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1083 'Use base::win::String16FromGUID instead.'
1084 ),
1085 True,
1086 (
1087 r'/base/win/win_util_unittest.cc'
1088 ),
1089 ),
1090 (
Avi Drissman7382afa02019-04-29 23:27:131091 'kCFAllocatorNull',
1092 (
1093 'The use of kCFAllocatorNull with the NoCopy creation of ',
1094 'CoreFoundation types is prohibited.',
1095 ),
1096 True,
1097 (),
1098 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291099 (
1100 'mojo::ConvertTo',
1101 (
1102 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1103 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1104 'StringTraits if you would like to convert between custom types and',
1105 'the wire format of mojom types.'
1106 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221107 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291108 (
1109 r'^third_party/blink/.*\.(cc|h)$',
1110 r'^content/renderer/.*\.(cc|h)$',
1111 ),
1112 ),
[email protected]127f18ec2012-06-16 05:05:591113)
1114
wnwenbdc444e2016-05-25 13:44:151115
mlamouria82272622014-09-16 18:45:041116_IPC_ENUM_TRAITS_DEPRECATED = (
1117 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501118 'See http://www.chromium.org/Home/chromium-security/education/'
1119 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041120
Stephen Martinis97a394142018-06-07 23:06:051121_LONG_PATH_ERROR = (
1122 'Some files included in this CL have file names that are too long (> 200'
1123 ' characters). If committed, these files will cause issues on Windows. See'
1124 ' https://crbug.com/612667 for more details.'
1125)
1126
Shenghua Zhangbfaa38b82017-11-16 21:58:021127_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041128 r".*[\\/]BuildHooksAndroidImpl\.java",
1129 r".*[\\/]LicenseContentProvider\.java",
1130 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281131 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021132]
[email protected]127f18ec2012-06-16 05:05:591133
Sean Kau46e29bc2017-08-28 16:31:161134# These paths contain test data and other known invalid JSON files.
1135_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041136 r'test[\\/]data[\\/]',
1137 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1138 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041139 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431140 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161141]
1142
1143
[email protected]b00342e7f2013-03-26 16:21:541144_VALID_OS_MACROS = (
1145 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081146 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541147 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121148 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541149 'OS_BSD',
1150 'OS_CAT', # For testing.
1151 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041152 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541153 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371154 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541155 'OS_IOS',
1156 'OS_LINUX',
1157 'OS_MACOSX',
1158 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211159 'OS_NACL_NONSFI',
1160 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121161 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541162 'OS_OPENBSD',
1163 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371164 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541165 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541166 'OS_WIN',
1167)
1168
1169
agrievef32bcc72016-04-04 14:57:401170_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391171 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361172 'base/android/jni_generator/jni_generator.pydeps',
1173 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221174 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361175 'build/android/gyp/aar.pydeps',
1176 'build/android/gyp/aidl.pydeps',
1177 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381178 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361179 'build/android/gyp/bytecode_processor.pydeps',
1180 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:571181 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361182 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1183 'build/android/gyp/copy_ex.pydeps',
1184 'build/android/gyp/create_app_bundle.pydeps',
1185 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361186 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221187 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361188 'build/android/gyp/create_tool_wrapper.pydeps',
1189 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591190 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361191 'build/android/gyp/dex.pydeps',
1192 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361193 'build/android/gyp/filter_zip.pydeps',
1194 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361195 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361196 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581197 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361198 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261199 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361200 'build/android/gyp/javac.pydeps',
1201 'build/android/gyp/jinja_template.pydeps',
1202 'build/android/gyp/lint.pydeps',
1203 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361204 'build/android/gyp/merge_manifest.pydeps',
1205 'build/android/gyp/prepare_resources.pydeps',
1206 'build/android/gyp/proguard.pydeps',
1207 'build/android/gyp/write_build_config.pydeps',
1208 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561209 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361210 'build/android/incremental_install/generate_android_manifest.pydeps',
1211 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221212 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401213 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041214 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361215 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411216 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:191217 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021218 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:401219]
1220
wnwenbdc444e2016-05-25 13:44:151221
agrievef32bcc72016-04-04 14:57:401222_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:401223 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:291224 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061225 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221226 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401227]
1228
wnwenbdc444e2016-05-25 13:44:151229
agrievef32bcc72016-04-04 14:57:401230_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1231
1232
Eric Boren6fd2b932018-01-25 15:05:081233# Bypass the AUTHORS check for these accounts.
1234_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:291235 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
1236 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:081237 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:321238 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:591239 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451240 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591241 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:221242 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041243 ) | set('%[email protected]' % s
1244 for s in ('chromium-autoroll',)
1245 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301246 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081247
1248
Daniel Bratell65b033262019-04-23 08:17:061249def _IsCPlusPlusFile(input_api, file_path):
1250 """Returns True if this file contains C++-like code (and not Python,
1251 Go, Java, MarkDown, ...)"""
1252
1253 ext = input_api.os_path.splitext(file_path)[1]
1254 # This list is compatible with CppChecker.IsCppFile but we should
1255 # consider adding ".c" to it. If we do that we can use this function
1256 # at more places in the code.
1257 return ext in (
1258 '.h',
1259 '.cc',
1260 '.cpp',
1261 '.m',
1262 '.mm',
1263 )
1264
1265def _IsCPlusPlusHeaderFile(input_api, file_path):
1266 return input_api.os_path.splitext(file_path)[1] == ".h"
1267
1268
1269def _IsJavaFile(input_api, file_path):
1270 return input_api.os_path.splitext(file_path)[1] == ".java"
1271
1272
1273def _IsProtoFile(input_api, file_path):
1274 return input_api.os_path.splitext(file_path)[1] == ".proto"
1275
[email protected]55459852011-08-10 15:17:191276def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1277 """Attempts to prevent use of functions intended only for testing in
1278 non-testing code. For now this is just a best-effort implementation
1279 that ignores header files and may have some false positives. A
1280 better implementation would probably need a proper C++ parser.
1281 """
1282 # We only scan .cc files and the like, as the declaration of
1283 # for-testing functions in header files are hard to distinguish from
1284 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491285 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191286
jochenc0d4808c2015-07-27 09:25:421287 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191288 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091289 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191290 exclusion_pattern = input_api.re.compile(
1291 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1292 base_function_pattern, base_function_pattern))
1293
1294 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441295 black_list = (_EXCLUDED_PATHS +
1296 _TEST_CODE_EXCLUDED_PATHS +
1297 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191298 return input_api.FilterSourceFile(
1299 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491300 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191301 black_list=black_list)
1302
1303 problems = []
1304 for f in input_api.AffectedSourceFiles(FilterFile):
1305 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241306 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031307 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461308 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031309 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191310 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031311 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191312
1313 if problems:
[email protected]f7051d52013-04-02 18:31:421314 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031315 else:
1316 return []
[email protected]55459852011-08-10 15:17:191317
1318
Vaclav Brozek7dbc28c2018-03-27 08:35:231319def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1320 """This is a simplified version of
1321 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1322 """
1323 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1324 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1325 name_pattern = r'ForTest(s|ing)?'
1326 # Describes an occurrence of "ForTest*" inside a // comment.
1327 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1328 # Catch calls.
1329 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1330 # Ignore definitions. (Comments are ignored separately.)
1331 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1332
1333 problems = []
1334 sources = lambda x: input_api.FilterSourceFile(
1335 x,
1336 black_list=(('(?i).*test', r'.*\/junit\/')
1337 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491338 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231339 )
1340 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1341 local_path = f.LocalPath()
1342 is_inside_javadoc = False
1343 for line_number, line in f.ChangedContents():
1344 if is_inside_javadoc and javadoc_end_re.search(line):
1345 is_inside_javadoc = False
1346 if not is_inside_javadoc and javadoc_start_re.search(line):
1347 is_inside_javadoc = True
1348 if is_inside_javadoc:
1349 continue
1350 if (inclusion_re.search(line) and
1351 not comment_re.search(line) and
1352 not exclusion_re.search(line)):
1353 problems.append(
1354 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1355
1356 if problems:
1357 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1358 else:
1359 return []
1360
1361
[email protected]10689ca2011-09-02 02:31:541362def _CheckNoIOStreamInHeaders(input_api, output_api):
1363 """Checks to make sure no .h files include <iostream>."""
1364 files = []
1365 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1366 input_api.re.MULTILINE)
1367 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1368 if not f.LocalPath().endswith('.h'):
1369 continue
1370 contents = input_api.ReadFile(f)
1371 if pattern.search(contents):
1372 files.append(f)
1373
1374 if len(files):
yolandyandaabc6d2016-04-18 18:29:391375 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061376 'Do not #include <iostream> in header files, since it inserts static '
1377 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541378 '#include <ostream>. See http://crbug.com/94794',
1379 files) ]
1380 return []
1381
Danil Chapovalov3518f362018-08-11 16:13:431382def _CheckNoStrCatRedefines(input_api, output_api):
1383 """Checks no windows headers with StrCat redefined are included directly."""
1384 files = []
1385 pattern_deny = input_api.re.compile(
1386 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1387 input_api.re.MULTILINE)
1388 pattern_allow = input_api.re.compile(
1389 r'^#include\s"base/win/windows_defines.inc"',
1390 input_api.re.MULTILINE)
1391 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1392 contents = input_api.ReadFile(f)
1393 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1394 files.append(f.LocalPath())
1395
1396 if len(files):
1397 return [output_api.PresubmitError(
1398 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1399 'directly since they pollute code with StrCat macro. Instead, '
1400 'include matching header from base/win. See http://crbug.com/856536',
1401 files) ]
1402 return []
1403
[email protected]10689ca2011-09-02 02:31:541404
[email protected]72df4e782012-06-21 16:28:181405def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521406 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181407 problems = []
1408 for f in input_api.AffectedFiles():
1409 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1410 continue
1411
1412 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041413 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181414 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1415
1416 if not problems:
1417 return []
1418 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1419 '\n'.join(problems))]
1420
Dominic Battre033531052018-09-24 15:45:341421def _CheckNoDISABLETypoInTests(input_api, output_api):
1422 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1423
1424 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1425 instead of DISABLED_. To filter false positives, reports are only generated
1426 if a corresponding MAYBE_ line exists.
1427 """
1428 problems = []
1429
1430 # The following two patterns are looked for in tandem - is a test labeled
1431 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1432 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1433 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1434
1435 # This is for the case that a test is disabled on all platforms.
1436 full_disable_pattern = input_api.re.compile(
1437 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1438 input_api.re.MULTILINE)
1439
Katie Df13948e2018-09-25 07:33:441440 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341441 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1442 continue
1443
1444 # Search for MABYE_, DISABLE_ pairs.
1445 disable_lines = {} # Maps of test name to line number.
1446 maybe_lines = {}
1447 for line_num, line in f.ChangedContents():
1448 disable_match = disable_pattern.search(line)
1449 if disable_match:
1450 disable_lines[disable_match.group(1)] = line_num
1451 maybe_match = maybe_pattern.search(line)
1452 if maybe_match:
1453 maybe_lines[maybe_match.group(1)] = line_num
1454
1455 # Search for DISABLE_ occurrences within a TEST() macro.
1456 disable_tests = set(disable_lines.keys())
1457 maybe_tests = set(maybe_lines.keys())
1458 for test in disable_tests.intersection(maybe_tests):
1459 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1460
1461 contents = input_api.ReadFile(f)
1462 full_disable_match = full_disable_pattern.search(contents)
1463 if full_disable_match:
1464 problems.append(' %s' % f.LocalPath())
1465
1466 if not problems:
1467 return []
1468 return [
1469 output_api.PresubmitPromptWarning(
1470 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1471 '\n'.join(problems))
1472 ]
1473
[email protected]72df4e782012-06-21 16:28:181474
danakj61c1aa22015-10-26 19:55:521475def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571476 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521477 errors = []
1478 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1479 input_api.re.MULTILINE)
1480 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1481 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1482 continue
1483 for lnum, line in f.ChangedContents():
1484 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171485 errors.append(output_api.PresubmitError(
1486 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571487 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171488 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521489 return errors
1490
1491
Makoto Shimazu3ad422cd2019-05-08 02:35:141492def _FindHistogramNameInChunk(histogram_name, chunk):
1493 """Tries to find a histogram name or prefix in a line.
1494
1495 Returns the existence of the histogram name, or None if it needs more chunk
1496 to determine."""
mcasasb7440c282015-02-04 14:52:191497 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1498 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141499 if '<affected-histogram' in chunk:
1500 # If the tag is not completed, needs more chunk to get the name.
1501 if not '>' in chunk:
1502 return None
1503 if not 'name="' in chunk:
1504 return False
1505 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1506 # expect the only attribute is the name.
1507 histogram_prefix = chunk.split('"')[1]
1508 return histogram_prefix in histogram_name
1509 # Typically the whole histogram name should in the line.
1510 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191511
1512
1513def _CheckUmaHistogramChanges(input_api, output_api):
1514 """Check that UMA histogram names in touched lines can still be found in other
1515 lines of the patch or in histograms.xml. Note that this check would not catch
1516 the reverse: changes in histograms.xml not matched in the code itself."""
1517 touched_histograms = []
1518 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471519 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1520 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1521 name_pattern = r'"(.*?)"'
1522 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1523 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1524 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1525 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1526 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171527 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191528 for f in input_api.AffectedFiles():
1529 # If histograms.xml itself is modified, keep the modified lines for later.
1530 if f.LocalPath().endswith(('histograms.xml')):
1531 histograms_xml_modifications = f.ChangedContents()
1532 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471533 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1534 single_line_re = single_line_c_re
1535 split_line_prefix_re = split_line_c_prefix_re
1536 elif f.LocalPath().endswith(('java')):
1537 single_line_re = single_line_java_re
1538 split_line_prefix_re = split_line_java_prefix_re
1539 else:
mcasasb7440c282015-02-04 14:52:191540 continue
1541 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171542 if last_line_matched_prefix:
1543 suffix_found = split_line_suffix_re.search(line)
1544 if suffix_found :
1545 touched_histograms.append([suffix_found.group(1), f, line_num])
1546 last_line_matched_prefix = False
1547 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061548 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191549 if found:
1550 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171551 continue
1552 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191553
1554 # Search for the touched histogram names in the local modifications to
1555 # histograms.xml, and, if not found, on the base histograms.xml file.
1556 unmatched_histograms = []
1557 for histogram_info in touched_histograms:
1558 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141559 chunk = ''
mcasasb7440c282015-02-04 14:52:191560 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141561 chunk += line
1562 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1563 if histogram_name_found is None:
1564 continue
1565 chunk = ''
mcasasb7440c282015-02-04 14:52:191566 if histogram_name_found:
1567 break
1568 if not histogram_name_found:
1569 unmatched_histograms.append(histogram_info)
1570
eromanb90c82e7e32015-04-01 15:13:491571 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191572 problems = []
1573 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491574 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191575 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451576 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191577 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141578 chunk = ''
mcasasb7440c282015-02-04 14:52:191579 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141580 chunk += line
1581 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1582 chunk)
1583 if histogram_name_found is None:
1584 continue
1585 chunk = ''
mcasasb7440c282015-02-04 14:52:191586 if histogram_name_found:
1587 break
1588 if not histogram_name_found:
1589 problems.append(' [%s:%d] %s' %
1590 (f.LocalPath(), line_num, histogram_name))
1591
1592 if not problems:
1593 return []
1594 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1595 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491596 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191597
wnwenbdc444e2016-05-25 13:44:151598
yolandyandaabc6d2016-04-18 18:29:391599def _CheckFlakyTestUsage(input_api, output_api):
1600 """Check that FlakyTest annotation is our own instead of the android one"""
1601 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1602 files = []
1603 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1604 if f.LocalPath().endswith('Test.java'):
1605 if pattern.search(input_api.ReadFile(f)):
1606 files.append(f)
1607 if len(files):
1608 return [output_api.PresubmitError(
1609 'Use org.chromium.base.test.util.FlakyTest instead of '
1610 'android.test.FlakyTest',
1611 files)]
1612 return []
mcasasb7440c282015-02-04 14:52:191613
wnwenbdc444e2016-05-25 13:44:151614
[email protected]8ea5d4b2011-09-13 21:49:221615def _CheckNoNewWStrings(input_api, output_api):
1616 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271617 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221618 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201619 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571620 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341621 '/win/' in f.LocalPath() or
1622 'chrome_elf' in f.LocalPath() or
1623 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201624 continue
[email protected]8ea5d4b2011-09-13 21:49:221625
[email protected]a11dbe9b2012-08-07 01:32:581626 allowWString = False
[email protected]b5c24292011-11-28 14:38:201627 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581628 if 'presubmit: allow wstring' in line:
1629 allowWString = True
1630 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271631 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581632 allowWString = False
1633 else:
1634 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221635
[email protected]55463aa62011-10-12 00:48:271636 if not problems:
1637 return []
1638 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581639 ' If you are calling a cross-platform API that accepts a wstring, '
1640 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271641 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221642
1643
[email protected]2a8ac9c2011-10-19 17:20:441644def _CheckNoDEPSGIT(input_api, output_api):
1645 """Make sure .DEPS.git is never modified manually."""
1646 if any(f.LocalPath().endswith('.DEPS.git') for f in
1647 input_api.AffectedFiles()):
1648 return [output_api.PresubmitError(
1649 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1650 'automated system based on what\'s in DEPS and your changes will be\n'
1651 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501652 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1653 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441654 'for more information')]
1655 return []
1656
1657
tandriief664692014-09-23 14:51:471658def _CheckValidHostsInDEPS(input_api, output_api):
1659 """Checks that DEPS file deps are from allowed_hosts."""
1660 # Run only if DEPS file has been modified to annoy fewer bystanders.
1661 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1662 return []
1663 # Outsource work to gclient verify
1664 try:
John Budorickf20c0042019-04-25 23:23:401665 gclient_path = input_api.os_path.join(
1666 input_api.PresubmitLocalPath(),
1667 'third_party', 'depot_tools', 'gclient.py')
1668 input_api.subprocess.check_output(
1669 [input_api.python_executable, gclient_path, 'verify'],
1670 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471671 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201672 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471673 return [output_api.PresubmitError(
1674 'DEPS file must have only git dependencies.',
1675 long_text=error.output)]
1676
1677
[email protected]127f18ec2012-06-16 05:05:591678def _CheckNoBannedFunctions(input_api, output_api):
1679 """Make sure that banned functions are not used."""
1680 warnings = []
1681 errors = []
1682
wnwenbdc444e2016-05-25 13:44:151683 def IsBlacklisted(affected_file, blacklist):
1684 local_path = affected_file.LocalPath()
1685 for item in blacklist:
1686 if input_api.re.match(item, local_path):
1687 return True
1688 return False
1689
Sylvain Defresnea8b73d252018-02-28 15:45:541690 def IsIosObcjFile(affected_file):
1691 local_path = affected_file.LocalPath()
1692 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1693 return False
1694 basename = input_api.os_path.basename(local_path)
1695 if 'ios' in basename.split('_'):
1696 return True
1697 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1698 if sep and 'ios' in local_path.split(sep):
1699 return True
1700 return False
1701
wnwenbdc444e2016-05-25 13:44:151702 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1703 matched = False
1704 if func_name[0:1] == '/':
1705 regex = func_name[1:]
1706 if input_api.re.search(regex, line):
1707 matched = True
1708 elif func_name in line:
dchenge07de812016-06-20 19:27:171709 matched = True
wnwenbdc444e2016-05-25 13:44:151710 if matched:
dchenge07de812016-06-20 19:27:171711 problems = warnings
wnwenbdc444e2016-05-25 13:44:151712 if error:
dchenge07de812016-06-20 19:27:171713 problems = errors
wnwenbdc444e2016-05-25 13:44:151714 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1715 for message_line in message:
1716 problems.append(' %s' % message_line)
1717
Eric Stevensona9a980972017-09-23 00:04:411718 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1719 for f in input_api.AffectedFiles(file_filter=file_filter):
1720 for line_num, line in f.ChangedContents():
1721 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1722 CheckForMatch(f, line_num, line, func_name, message, error)
1723
[email protected]127f18ec2012-06-16 05:05:591724 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1725 for f in input_api.AffectedFiles(file_filter=file_filter):
1726 for line_num, line in f.ChangedContents():
1727 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151728 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591729
Sylvain Defresnea8b73d252018-02-28 15:45:541730 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1731 for line_num, line in f.ChangedContents():
1732 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1733 CheckForMatch(f, line_num, line, func_name, message, error)
1734
[email protected]127f18ec2012-06-16 05:05:591735 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1736 for f in input_api.AffectedFiles(file_filter=file_filter):
1737 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491738 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491739 if IsBlacklisted(f, excluded_paths):
1740 continue
wnwenbdc444e2016-05-25 13:44:151741 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591742
1743 result = []
1744 if (warnings):
1745 result.append(output_api.PresubmitPromptWarning(
1746 'Banned functions were used.\n' + '\n'.join(warnings)))
1747 if (errors):
1748 result.append(output_api.PresubmitError(
1749 'Banned functions were used.\n' + '\n'.join(errors)))
1750 return result
1751
1752
[email protected]6c063c62012-07-11 19:11:061753def _CheckNoPragmaOnce(input_api, output_api):
1754 """Make sure that banned functions are not used."""
1755 files = []
1756 pattern = input_api.re.compile(r'^#pragma\s+once',
1757 input_api.re.MULTILINE)
1758 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1759 if not f.LocalPath().endswith('.h'):
1760 continue
1761 contents = input_api.ReadFile(f)
1762 if pattern.search(contents):
1763 files.append(f)
1764
1765 if files:
1766 return [output_api.PresubmitError(
1767 'Do not use #pragma once in header files.\n'
1768 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1769 files)]
1770 return []
1771
[email protected]127f18ec2012-06-16 05:05:591772
[email protected]e7479052012-09-19 00:26:121773def _CheckNoTrinaryTrueFalse(input_api, output_api):
1774 """Checks to make sure we don't introduce use of foo ? true : false."""
1775 problems = []
1776 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1777 for f in input_api.AffectedFiles():
1778 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1779 continue
1780
1781 for line_num, line in f.ChangedContents():
1782 if pattern.match(line):
1783 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1784
1785 if not problems:
1786 return []
1787 return [output_api.PresubmitPromptWarning(
1788 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1789 '\n'.join(problems))]
1790
1791
[email protected]55f9f382012-07-31 11:02:181792def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281793 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181794 change. Breaking - rules is an error, breaking ! rules is a
1795 warning.
1796 """
mohan.reddyf21db962014-10-16 12:26:471797 import sys
[email protected]55f9f382012-07-31 11:02:181798 # We need to wait until we have an input_api object and use this
1799 # roundabout construct to import checkdeps because this file is
1800 # eval-ed and thus doesn't have __file__.
1801 original_sys_path = sys.path
1802 try:
1803 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471804 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181805 import checkdeps
[email protected]55f9f382012-07-31 11:02:181806 from rules import Rule
1807 finally:
1808 # Restore sys.path to what it was before.
1809 sys.path = original_sys_path
1810
1811 added_includes = []
rhalavati08acd232017-04-03 07:23:281812 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241813 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181814 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061815 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501816 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081817 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061818 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501819 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081820 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061821 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501822 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081823 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181824
[email protected]26385172013-05-09 23:11:351825 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181826
1827 error_descriptions = []
1828 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281829 error_subjects = set()
1830 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181831 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1832 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081833 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181834 description_with_path = '%s\n %s' % (path, rule_description)
1835 if rule_type == Rule.DISALLOW:
1836 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281837 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181838 else:
1839 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281840 warning_subjects.add("#includes")
1841
1842 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1843 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081844 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281845 description_with_path = '%s\n %s' % (path, rule_description)
1846 if rule_type == Rule.DISALLOW:
1847 error_descriptions.append(description_with_path)
1848 error_subjects.add("imports")
1849 else:
1850 warning_descriptions.append(description_with_path)
1851 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181852
Jinsuk Kim5a092672017-10-24 22:42:241853 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021854 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081855 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241856 description_with_path = '%s\n %s' % (path, rule_description)
1857 if rule_type == Rule.DISALLOW:
1858 error_descriptions.append(description_with_path)
1859 error_subjects.add("imports")
1860 else:
1861 warning_descriptions.append(description_with_path)
1862 warning_subjects.add("imports")
1863
[email protected]55f9f382012-07-31 11:02:181864 results = []
1865 if error_descriptions:
1866 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281867 'You added one or more %s that violate checkdeps rules.'
1868 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181869 error_descriptions))
1870 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421871 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281872 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181873 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281874 '%s? See relevant DEPS file(s) for details and contacts.' %
1875 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181876 warning_descriptions))
1877 return results
1878
1879
[email protected]fbcafe5a2012-08-08 15:31:221880def _CheckFilePermissions(input_api, output_api):
1881 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151882 if input_api.platform == 'win32':
1883 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291884 checkperms_tool = input_api.os_path.join(
1885 input_api.PresubmitLocalPath(),
1886 'tools', 'checkperms', 'checkperms.py')
1887 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471888 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391889 with input_api.CreateTemporaryFile() as file_list:
1890 for f in input_api.AffectedFiles():
1891 # checkperms.py file/directory arguments must be relative to the
1892 # repository.
1893 file_list.write(f.LocalPath() + '\n')
1894 file_list.close()
1895 args += ['--file-list', file_list.name]
1896 try:
1897 input_api.subprocess.check_output(args)
1898 return []
1899 except input_api.subprocess.CalledProcessError as error:
1900 return [output_api.PresubmitError(
1901 'checkperms.py failed:',
1902 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221903
1904
robertocn832f5992017-01-04 19:01:301905def _CheckTeamTags(input_api, output_api):
1906 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1907 checkteamtags_tool = input_api.os_path.join(
1908 input_api.PresubmitLocalPath(),
1909 'tools', 'checkteamtags', 'checkteamtags.py')
1910 args = [input_api.python_executable, checkteamtags_tool,
1911 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221912 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301913 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1914 'OWNERS']
1915 try:
1916 if files:
1917 input_api.subprocess.check_output(args + files)
1918 return []
1919 except input_api.subprocess.CalledProcessError as error:
1920 return [output_api.PresubmitError(
1921 'checkteamtags.py failed:',
1922 long_text=error.output)]
1923
1924
[email protected]c8278b32012-10-30 20:35:491925def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1926 """Makes sure we don't include ui/aura/window_property.h
1927 in header files.
1928 """
1929 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1930 errors = []
1931 for f in input_api.AffectedFiles():
1932 if not f.LocalPath().endswith('.h'):
1933 continue
1934 for line_num, line in f.ChangedContents():
1935 if pattern.match(line):
1936 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1937
1938 results = []
1939 if errors:
1940 results.append(output_api.PresubmitError(
1941 'Header files should not include ui/aura/window_property.h', errors))
1942 return results
1943
1944
[email protected]70ca77752012-11-20 03:45:031945def _CheckForVersionControlConflictsInFile(input_api, f):
1946 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1947 errors = []
1948 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161949 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231950 # First-level headers in markdown look a lot like version control
1951 # conflict markers. http://daringfireball.net/projects/markdown/basics
1952 continue
[email protected]70ca77752012-11-20 03:45:031953 if pattern.match(line):
1954 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1955 return errors
1956
1957
1958def _CheckForVersionControlConflicts(input_api, output_api):
1959 """Usually this is not intentional and will cause a compile failure."""
1960 errors = []
1961 for f in input_api.AffectedFiles():
1962 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1963
1964 results = []
1965 if errors:
1966 results.append(output_api.PresubmitError(
1967 'Version control conflict markers found, please resolve.', errors))
1968 return results
1969
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201970
estadee17314a02017-01-12 16:22:161971def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1972 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1973 errors = []
1974 for f in input_api.AffectedFiles():
1975 for line_num, line in f.ChangedContents():
1976 if pattern.search(line):
1977 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1978
1979 results = []
1980 if errors:
1981 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501982 'Found Google support URL addressed by answer number. Please replace '
1983 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161984 return results
1985
[email protected]70ca77752012-11-20 03:45:031986
[email protected]06e6d0ff2012-12-11 01:36:441987def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1988 def FilterFile(affected_file):
1989 """Filter function for use with input_api.AffectedSourceFiles,
1990 below. This filters out everything except non-test files from
1991 top-level directories that generally speaking should not hard-code
1992 service URLs (e.g. src/android_webview/, src/content/ and others).
1993 """
1994 return input_api.FilterSourceFile(
1995 affected_file,
Egor Paskoce145c42018-09-28 19:31:041996 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441997 black_list=(_EXCLUDED_PATHS +
1998 _TEST_CODE_EXCLUDED_PATHS +
1999 input_api.DEFAULT_BLACK_LIST))
2000
reillyi38965732015-11-16 18:27:332001 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2002 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462003 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2004 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442005 problems = [] # items are (filename, line_number, line)
2006 for f in input_api.AffectedSourceFiles(FilterFile):
2007 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462008 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442009 problems.append((f.LocalPath(), line_num, line))
2010
2011 if problems:
[email protected]f7051d52013-04-02 18:31:422012 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442013 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582014 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442015 [' %s:%d: %s' % (
2016 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032017 else:
2018 return []
[email protected]06e6d0ff2012-12-11 01:36:442019
2020
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492021# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272022def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2023 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312024 The native_client_sdk directory is excluded because it has auto-generated PNG
2025 files for documentation.
[email protected]d2530012013-01-25 16:39:272026 """
[email protected]d2530012013-01-25 16:39:272027 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492028 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042029 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312030 file_filter = lambda f: input_api.FilterSourceFile(
2031 f, white_list=white_list, black_list=black_list)
2032 for f in input_api.AffectedFiles(include_deletes=False,
2033 file_filter=file_filter):
2034 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272035
2036 results = []
2037 if errors:
2038 results.append(output_api.PresubmitError(
2039 'The name of PNG files should not have abbreviations. \n'
2040 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2041 'Contact [email protected] if you have questions.', errors))
2042 return results
2043
2044
Daniel Cheng4dcdb6b2017-04-13 08:30:172045def _ExtractAddRulesFromParsedDeps(parsed_deps):
2046 """Extract the rules that add dependencies from a parsed DEPS file.
2047
2048 Args:
2049 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2050 add_rules = set()
2051 add_rules.update([
2052 rule[1:] for rule in parsed_deps.get('include_rules', [])
2053 if rule.startswith('+') or rule.startswith('!')
2054 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502055 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172056 {}).iteritems():
2057 add_rules.update([
2058 rule[1:] for rule in rules
2059 if rule.startswith('+') or rule.startswith('!')
2060 ])
2061 return add_rules
2062
2063
2064def _ParseDeps(contents):
2065 """Simple helper for parsing DEPS files."""
2066 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172067 class _VarImpl:
2068
2069 def __init__(self, local_scope):
2070 self._local_scope = local_scope
2071
2072 def Lookup(self, var_name):
2073 """Implements the Var syntax."""
2074 try:
2075 return self._local_scope['vars'][var_name]
2076 except KeyError:
2077 raise Exception('Var is not defined: %s' % var_name)
2078
2079 local_scope = {}
2080 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172081 'Var': _VarImpl(local_scope).Lookup,
2082 }
2083 exec contents in global_scope, local_scope
2084 return local_scope
2085
2086
2087def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082088 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412089 a set of DEPS entries that we should look up.
2090
2091 For a directory (rather than a specific filename) we fake a path to
2092 a specific filename by adding /DEPS. This is chosen as a file that
2093 will seldom or never be subject to per-file include_rules.
2094 """
[email protected]2b438d62013-11-14 17:54:142095 # We ignore deps entries on auto-generated directories.
2096 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082097
Daniel Cheng4dcdb6b2017-04-13 08:30:172098 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2099 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2100
2101 added_deps = new_deps.difference(old_deps)
2102
[email protected]2b438d62013-11-14 17:54:142103 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172104 for added_dep in added_deps:
2105 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2106 continue
2107 # Assume that a rule that ends in .h is a rule for a specific file.
2108 if added_dep.endswith('.h'):
2109 results.add(added_dep)
2110 else:
2111 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082112 return results
2113
2114
[email protected]e871964c2013-05-13 14:14:552115def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2116 """When a dependency prefixed with + is added to a DEPS file, we
2117 want to make sure that the change is reviewed by an OWNER of the
2118 target file or directory, to avoid layering violations from being
2119 introduced. This check verifies that this happens.
2120 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172121 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242122
2123 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492124 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242125 for f in input_api.AffectedFiles(include_deletes=False,
2126 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552127 filename = input_api.os_path.basename(f.LocalPath())
2128 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172129 virtual_depended_on_files.update(_CalculateAddedDeps(
2130 input_api.os_path,
2131 '\n'.join(f.OldContents()),
2132 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552133
[email protected]e871964c2013-05-13 14:14:552134 if not virtual_depended_on_files:
2135 return []
2136
2137 if input_api.is_committing:
2138 if input_api.tbr:
2139 return [output_api.PresubmitNotifyResult(
2140 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272141 if input_api.dry_run:
2142 return [output_api.PresubmitNotifyResult(
2143 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552144 if not input_api.change.issue:
2145 return [output_api.PresubmitError(
2146 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402147 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552148 output = output_api.PresubmitError
2149 else:
2150 output = output_api.PresubmitNotifyResult
2151
2152 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502153 owner_email, reviewers = (
2154 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2155 input_api,
2156 owners_db.email_regexp,
2157 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552158
2159 owner_email = owner_email or input_api.change.author_email
2160
[email protected]de4f7d22013-05-23 14:27:462161 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512162 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462163 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552164 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2165 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412166
2167 # We strip the /DEPS part that was added by
2168 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2169 # directory.
2170 def StripDeps(path):
2171 start_deps = path.rfind('/DEPS')
2172 if start_deps != -1:
2173 return path[:start_deps]
2174 else:
2175 return path
2176 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552177 for path in missing_files]
2178
2179 if unapproved_dependencies:
2180 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152181 output('You need LGTM from owners of depends-on paths in DEPS that were '
2182 'modified in this CL:\n %s' %
2183 '\n '.join(sorted(unapproved_dependencies)))]
2184 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2185 output_list.append(output(
2186 'Suggested missing target path OWNERS:\n %s' %
2187 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552188 return output_list
2189
2190 return []
2191
2192
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492193# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402194def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492195 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402196 black_list = (_EXCLUDED_PATHS +
2197 _TEST_CODE_EXCLUDED_PATHS +
2198 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042199 (r"^base[\\/]logging\.h$",
2200 r"^base[\\/]logging\.cc$",
2201 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2202 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2203 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122204 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182205 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152206 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032207 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152208 r"^chrome[\\/]chrome_cleaner[\\/].*",
2209 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2210 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042211 r"^chromecast[\\/]",
2212 r"^cloud_print[\\/]",
2213 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482214 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:042215 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:312216 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042217 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462218 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042219 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462220 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042221 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252222 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042223 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2224 r"^courgette[\\/]courgette_tool\.cc$",
2225 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272226 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332227 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042228 r"^ipc[\\/]ipc_logging\.cc$",
2229 r"^native_client_sdk[\\/]",
2230 r"^remoting[\\/]base[\\/]logging\.h$",
2231 r"^remoting[\\/]host[\\/].*",
2232 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332233 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
2234 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042235 r"^tools[\\/]",
2236 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2237 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332238 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402239 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492240 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402241
thomasanderson625d3932017-03-29 07:16:582242 log_info = set([])
2243 printf = set([])
[email protected]85218562013-11-22 07:41:402244
2245 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582246 for _, line in f.ChangedContents():
2247 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2248 log_info.add(f.LocalPath())
2249 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2250 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372251
thomasanderson625d3932017-03-29 07:16:582252 if input_api.re.search(r"\bprintf\(", line):
2253 printf.add(f.LocalPath())
2254 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2255 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402256
2257 if log_info:
2258 return [output_api.PresubmitError(
2259 'These files spam the console log with LOG(INFO):',
2260 items=log_info)]
2261 if printf:
2262 return [output_api.PresubmitError(
2263 'These files spam the console log with printf/fprintf:',
2264 items=printf)]
2265 return []
2266
2267
[email protected]49aa76a2013-12-04 06:59:162268def _CheckForAnonymousVariables(input_api, output_api):
2269 """These types are all expected to hold locks while in scope and
2270 so should never be anonymous (which causes them to be immediately
2271 destroyed)."""
2272 they_who_must_be_named = [
2273 'base::AutoLock',
2274 'base::AutoReset',
2275 'base::AutoUnlock',
2276 'SkAutoAlphaRestore',
2277 'SkAutoBitmapShaderInstall',
2278 'SkAutoBlitterChoose',
2279 'SkAutoBounderCommit',
2280 'SkAutoCallProc',
2281 'SkAutoCanvasRestore',
2282 'SkAutoCommentBlock',
2283 'SkAutoDescriptor',
2284 'SkAutoDisableDirectionCheck',
2285 'SkAutoDisableOvalCheck',
2286 'SkAutoFree',
2287 'SkAutoGlyphCache',
2288 'SkAutoHDC',
2289 'SkAutoLockColors',
2290 'SkAutoLockPixels',
2291 'SkAutoMalloc',
2292 'SkAutoMaskFreeImage',
2293 'SkAutoMutexAcquire',
2294 'SkAutoPathBoundsUpdate',
2295 'SkAutoPDFRelease',
2296 'SkAutoRasterClipValidate',
2297 'SkAutoRef',
2298 'SkAutoTime',
2299 'SkAutoTrace',
2300 'SkAutoUnref',
2301 ]
2302 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2303 # bad: base::AutoLock(lock.get());
2304 # not bad: base::AutoLock lock(lock.get());
2305 bad_pattern = input_api.re.compile(anonymous)
2306 # good: new base::AutoLock(lock.get())
2307 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2308 errors = []
2309
2310 for f in input_api.AffectedFiles():
2311 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2312 continue
2313 for linenum, line in f.ChangedContents():
2314 if bad_pattern.search(line) and not good_pattern.search(line):
2315 errors.append('%s:%d' % (f.LocalPath(), linenum))
2316
2317 if errors:
2318 return [output_api.PresubmitError(
2319 'These lines create anonymous variables that need to be named:',
2320 items=errors)]
2321 return []
2322
2323
Peter Kasting4844e46e2018-02-23 07:27:102324def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532325 # Returns whether |template_str| is of the form <T, U...> for some types T
2326 # and U. Assumes that |template_str| is already in the form <...>.
2327 def HasMoreThanOneArg(template_str):
2328 # Level of <...> nesting.
2329 nesting = 0
2330 for c in template_str:
2331 if c == '<':
2332 nesting += 1
2333 elif c == '>':
2334 nesting -= 1
2335 elif c == ',' and nesting == 1:
2336 return True
2337 return False
2338
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492339 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102340 sources = lambda affected_file: input_api.FilterSourceFile(
2341 affected_file,
2342 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2343 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492344 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552345
2346 # Pattern to capture a single "<...>" block of template arguments. It can
2347 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2348 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2349 # latter would likely require counting that < and > match, which is not
2350 # expressible in regular languages. Should the need arise, one can introduce
2351 # limited counting (matching up to a total number of nesting depth), which
2352 # should cover all practical cases for already a low nesting limit.
2353 template_arg_pattern = (
2354 r'<[^>]*' # Opening block of <.
2355 r'>([^<]*>)?') # Closing block of >.
2356 # Prefix expressing that whatever follows is not already inside a <...>
2357 # block.
2358 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102359 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552360 not_inside_template_arg_pattern
2361 + r'\bstd::unique_ptr'
2362 + template_arg_pattern
2363 + r'\(\)')
2364
2365 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2366 template_arg_no_array_pattern = (
2367 r'<[^>]*[^]]' # Opening block of <.
2368 r'>([^(<]*[^]]>)?') # Closing block of >.
2369 # Prefix saying that what follows is the start of an expression.
2370 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2371 # Suffix saying that what follows are call parentheses with a non-empty list
2372 # of arguments.
2373 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532374 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552375 return_construct_pattern = input_api.re.compile(
2376 start_of_expr_pattern
2377 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532378 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552379 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532380 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552381 + nonempty_arg_list_pattern)
2382
Vaclav Brozek851d9602018-04-04 16:13:052383 problems_constructor = []
2384 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102385 for f in input_api.AffectedSourceFiles(sources):
2386 for line_number, line in f.ChangedContents():
2387 # Disallow:
2388 # return std::unique_ptr<T>(foo);
2389 # bar = std::unique_ptr<T>(foo);
2390 # But allow:
2391 # return std::unique_ptr<T[]>(foo);
2392 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532393 # And also allow cases when the second template argument is present. Those
2394 # cases cannot be handled by std::make_unique:
2395 # return std::unique_ptr<T, U>(foo);
2396 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052397 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532398 return_construct_result = return_construct_pattern.search(line)
2399 if return_construct_result and not HasMoreThanOneArg(
2400 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052401 problems_constructor.append(
2402 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102403 # Disallow:
2404 # std::unique_ptr<T>()
2405 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052406 problems_nullptr.append(
2407 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2408
2409 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162410 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052411 errors.append(output_api.PresubmitError(
2412 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162413 problems_nullptr))
2414 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052415 errors.append(output_api.PresubmitError(
2416 'The following files use explicit std::unique_ptr constructor.'
2417 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162418 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102419 return errors
2420
2421
[email protected]999261d2014-03-03 20:08:082422def _CheckUserActionUpdate(input_api, output_api):
2423 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522424 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082425 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522426 # If actions.xml is already included in the changelist, the PRESUBMIT
2427 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082428 return []
2429
[email protected]999261d2014-03-03 20:08:082430 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2431 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522432 current_actions = None
[email protected]999261d2014-03-03 20:08:082433 for f in input_api.AffectedFiles(file_filter=file_filter):
2434 for line_num, line in f.ChangedContents():
2435 match = input_api.re.search(action_re, line)
2436 if match:
[email protected]2f92dec2014-03-07 19:21:522437 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2438 # loaded only once.
2439 if not current_actions:
2440 with open('tools/metrics/actions/actions.xml') as actions_f:
2441 current_actions = actions_f.read()
2442 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082443 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522444 action = 'name="{0}"'.format(action_name)
2445 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082446 return [output_api.PresubmitPromptWarning(
2447 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522448 'tools/metrics/actions/actions.xml. Please run '
2449 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082450 % (f.LocalPath(), line_num, action_name))]
2451 return []
2452
2453
Daniel Cheng13ca61a882017-08-25 15:11:252454def _ImportJSONCommentEater(input_api):
2455 import sys
2456 sys.path = sys.path + [input_api.os_path.join(
2457 input_api.PresubmitLocalPath(),
2458 'tools', 'json_comment_eater')]
2459 import json_comment_eater
2460 return json_comment_eater
2461
2462
[email protected]99171a92014-06-03 08:44:472463def _GetJSONParseError(input_api, filename, eat_comments=True):
2464 try:
2465 contents = input_api.ReadFile(filename)
2466 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252467 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132468 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472469
2470 input_api.json.loads(contents)
2471 except ValueError as e:
2472 return e
2473 return None
2474
2475
2476def _GetIDLParseError(input_api, filename):
2477 try:
2478 contents = input_api.ReadFile(filename)
2479 idl_schema = input_api.os_path.join(
2480 input_api.PresubmitLocalPath(),
2481 'tools', 'json_schema_compiler', 'idl_schema.py')
2482 process = input_api.subprocess.Popen(
2483 [input_api.python_executable, idl_schema],
2484 stdin=input_api.subprocess.PIPE,
2485 stdout=input_api.subprocess.PIPE,
2486 stderr=input_api.subprocess.PIPE,
2487 universal_newlines=True)
2488 (_, error) = process.communicate(input=contents)
2489 return error or None
2490 except ValueError as e:
2491 return e
2492
2493
2494def _CheckParseErrors(input_api, output_api):
2495 """Check that IDL and JSON files do not contain syntax errors."""
2496 actions = {
2497 '.idl': _GetIDLParseError,
2498 '.json': _GetJSONParseError,
2499 }
[email protected]99171a92014-06-03 08:44:472500 # Most JSON files are preprocessed and support comments, but these do not.
2501 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042502 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472503 ]
2504 # Only run IDL checker on files in these directories.
2505 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042506 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2507 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472508 ]
2509
2510 def get_action(affected_file):
2511 filename = affected_file.LocalPath()
2512 return actions.get(input_api.os_path.splitext(filename)[1])
2513
[email protected]99171a92014-06-03 08:44:472514 def FilterFile(affected_file):
2515 action = get_action(affected_file)
2516 if not action:
2517 return False
2518 path = affected_file.LocalPath()
2519
Sean Kau46e29bc2017-08-28 16:31:162520 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472521 return False
2522
2523 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162524 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472525 return False
2526 return True
2527
2528 results = []
2529 for affected_file in input_api.AffectedFiles(
2530 file_filter=FilterFile, include_deletes=False):
2531 action = get_action(affected_file)
2532 kwargs = {}
2533 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162534 _MatchesFile(input_api, json_no_comments_patterns,
2535 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472536 kwargs['eat_comments'] = False
2537 parse_error = action(input_api,
2538 affected_file.AbsoluteLocalPath(),
2539 **kwargs)
2540 if parse_error:
2541 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2542 (affected_file.LocalPath(), parse_error)))
2543 return results
2544
2545
[email protected]760deea2013-12-10 19:33:492546def _CheckJavaStyle(input_api, output_api):
2547 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472548 import sys
[email protected]760deea2013-12-10 19:33:492549 original_sys_path = sys.path
2550 try:
2551 sys.path = sys.path + [input_api.os_path.join(
2552 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2553 import checkstyle
2554 finally:
2555 # Restore sys.path to what it was before.
2556 sys.path = original_sys_path
2557
2558 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092559 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512560 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492561
2562
Sean Kau46e29bc2017-08-28 16:31:162563def _MatchesFile(input_api, patterns, path):
2564 for pattern in patterns:
2565 if input_api.re.search(pattern, path):
2566 return True
2567 return False
2568
2569
Daniel Cheng7052cdf2017-11-21 19:23:292570def _GetOwnersFilesToCheckForIpcOwners(input_api):
2571 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172572
Daniel Cheng7052cdf2017-11-21 19:23:292573 Returns:
2574 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2575 contain to cover IPC-related files with noparent reviewer rules.
2576 """
2577 # Whether or not a file affects IPC is (mostly) determined by a simple list
2578 # of filename patterns.
dchenge07de812016-06-20 19:27:172579 file_patterns = [
palmerb19a0932017-01-24 04:00:312580 # Legacy IPC:
dchenge07de812016-06-20 19:27:172581 '*_messages.cc',
2582 '*_messages*.h',
2583 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312584 # Mojo IPC:
dchenge07de812016-06-20 19:27:172585 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472586 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172587 '*_struct_traits*.*',
2588 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312589 '*.typemap',
2590 # Android native IPC:
2591 '*.aidl',
2592 # Blink uses a different file naming convention:
2593 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472594 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172595 '*StructTraits*.*',
2596 '*TypeConverter*.*',
2597 ]
2598
scottmg7a6ed5ba2016-11-04 18:22:042599 # These third_party directories do not contain IPCs, but contain files
2600 # matching the above patterns, which trigger false positives.
2601 exclude_paths = [
2602 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232603 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062604 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292605 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042606 ]
2607
dchenge07de812016-06-20 19:27:172608 # Dictionary mapping an OWNERS file path to Patterns.
2609 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2610 # rules ) to a PatternEntry.
2611 # PatternEntry is a dictionary with two keys:
2612 # - 'files': the files that are matched by this pattern
2613 # - 'rules': the per-file rules needed for this pattern
2614 # For example, if we expect OWNERS file to contain rules for *.mojom and
2615 # *_struct_traits*.*, Patterns might look like this:
2616 # {
2617 # '*.mojom': {
2618 # 'files': ...,
2619 # 'rules': [
2620 # 'per-file *.mojom=set noparent',
2621 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2622 # ],
2623 # },
2624 # '*_struct_traits*.*': {
2625 # 'files': ...,
2626 # 'rules': [
2627 # 'per-file *_struct_traits*.*=set noparent',
2628 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2629 # ],
2630 # },
2631 # }
2632 to_check = {}
2633
Daniel Cheng13ca61a882017-08-25 15:11:252634 def AddPatternToCheck(input_file, pattern):
2635 owners_file = input_api.os_path.join(
2636 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2637 if owners_file not in to_check:
2638 to_check[owners_file] = {}
2639 if pattern not in to_check[owners_file]:
2640 to_check[owners_file][pattern] = {
2641 'files': [],
2642 'rules': [
2643 'per-file %s=set noparent' % pattern,
2644 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2645 ]
2646 }
Vaclav Brozekd5de76a2018-03-17 07:57:502647 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252648
dchenge07de812016-06-20 19:27:172649 # Iterate through the affected files to see what we actually need to check
2650 # for. We should only nag patch authors about per-file rules if a file in that
2651 # directory would match that pattern. If a directory only contains *.mojom
2652 # files and no *_messages*.h files, we should only nag about rules for
2653 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252654 for f in input_api.AffectedFiles(include_deletes=False):
2655 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362656 # affected files for .json, .cc, and .h files which look like they contain
2657 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162658 if (f.LocalPath().endswith('.json') and
2659 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2660 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252661 json_comment_eater = _ImportJSONCommentEater(input_api)
2662 mostly_json_lines = '\n'.join(f.NewContents())
2663 # Comments aren't allowed in strict JSON, so filter them out.
2664 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432665 try:
2666 json_content = input_api.json.loads(json_lines)
2667 except:
2668 # There's another PRESUBMIT check that already verifies that JSON files
2669 # are not invalid, so no need to emit another warning here.
2670 continue
Daniel Cheng13ca61a882017-08-25 15:11:252671 if 'interface_provider_specs' in json_content:
2672 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362673 else:
2674 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2675 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2676 if (manifest_pattern.search(f.LocalPath()) and not
2677 test_manifest_pattern.search(f.LocalPath())):
2678 # We expect all actual service manifest files to contain at least one
2679 # qualified reference to service_manager::Manifest.
2680 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2681 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172682 for pattern in file_patterns:
2683 if input_api.fnmatch.fnmatch(
2684 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042685 skip = False
2686 for exclude in exclude_paths:
2687 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2688 skip = True
2689 break
2690 if skip:
2691 continue
Daniel Cheng13ca61a882017-08-25 15:11:252692 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172693 break
2694
Daniel Cheng7052cdf2017-11-21 19:23:292695 return to_check
2696
2697
2698def _CheckIpcOwners(input_api, output_api):
2699 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2700 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2701
2702 if to_check:
2703 # If there are any OWNERS files to check, there are IPC-related changes in
2704 # this CL. Auto-CC the review list.
2705 output_api.AppendCC('[email protected]')
2706
2707 # Go through the OWNERS files to check, filtering out rules that are already
2708 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172709 for owners_file, patterns in to_check.iteritems():
2710 try:
2711 with file(owners_file) as f:
2712 lines = set(f.read().splitlines())
2713 for entry in patterns.itervalues():
2714 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2715 ]
2716 except IOError:
2717 # No OWNERS file, so all the rules are definitely missing.
2718 continue
2719
2720 # All the remaining lines weren't found in OWNERS files, so emit an error.
2721 errors = []
2722 for owners_file, patterns in to_check.iteritems():
2723 missing_lines = []
2724 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502725 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172726 missing_lines.extend(entry['rules'])
2727 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2728 if missing_lines:
2729 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052730 'Because of the presence of files:\n%s\n\n'
2731 '%s needs the following %d lines added:\n\n%s' %
2732 ('\n'.join(files), owners_file, len(missing_lines),
2733 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172734
2735 results = []
2736 if errors:
vabrf5ce3bf92016-07-11 14:52:412737 if input_api.is_committing:
2738 output = output_api.PresubmitError
2739 else:
2740 output = output_api.PresubmitPromptWarning
2741 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592742 'Found OWNERS files that need to be updated for IPC security ' +
2743 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172744 long_text='\n\n'.join(errors)))
2745
2746 return results
2747
2748
jbriance9e12f162016-11-25 07:57:502749def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312750 """Checks that added or removed lines in non third party affected
2751 header files do not lead to new useless class or struct forward
2752 declaration.
jbriance9e12f162016-11-25 07:57:502753 """
2754 results = []
2755 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2756 input_api.re.MULTILINE)
2757 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2758 input_api.re.MULTILINE)
2759 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312760 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192761 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492762 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312763 continue
2764
jbriance9e12f162016-11-25 07:57:502765 if not f.LocalPath().endswith('.h'):
2766 continue
2767
2768 contents = input_api.ReadFile(f)
2769 fwd_decls = input_api.re.findall(class_pattern, contents)
2770 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2771
2772 useless_fwd_decls = []
2773 for decl in fwd_decls:
2774 count = sum(1 for _ in input_api.re.finditer(
2775 r'\b%s\b' % input_api.re.escape(decl), contents))
2776 if count == 1:
2777 useless_fwd_decls.append(decl)
2778
2779 if not useless_fwd_decls:
2780 continue
2781
2782 for line in f.GenerateScmDiff().splitlines():
2783 if (line.startswith('-') and not line.startswith('--') or
2784 line.startswith('+') and not line.startswith('++')):
2785 for decl in useless_fwd_decls:
2786 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2787 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242788 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502789 (f.LocalPath(), decl)))
2790 useless_fwd_decls.remove(decl)
2791
2792 return results
2793
Jinsong Fan91ebbbd2019-04-16 14:57:172794def _CheckAndroidDebuggableBuild(input_api, output_api):
2795 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2796 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2797 this is a debuggable build of Android.
2798 """
2799 build_type_check_pattern = input_api.re.compile(
2800 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2801
2802 errors = []
2803
2804 sources = lambda affected_file: input_api.FilterSourceFile(
2805 affected_file,
2806 black_list=(_EXCLUDED_PATHS +
2807 _TEST_CODE_EXCLUDED_PATHS +
2808 input_api.DEFAULT_BLACK_LIST +
2809 (r"^android_webview[\\/]support_library[\\/]"
2810 "boundary_interfaces[\\/]",
2811 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2812 r'^third_party[\\/].*',
2813 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2814 r"webview[\\/]chromium[\\/]License.*",)),
2815 white_list=[r'.*\.java$'])
2816
2817 for f in input_api.AffectedSourceFiles(sources):
2818 for line_num, line in f.ChangedContents():
2819 if build_type_check_pattern.search(line):
2820 errors.append("%s:%d" % (f.LocalPath(), line_num))
2821
2822 results = []
2823
2824 if errors:
2825 results.append(output_api.PresubmitPromptWarning(
2826 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2827 ' Please use BuildInfo.isDebugAndroid() instead.',
2828 errors))
2829
2830 return results
jbriance9e12f162016-11-25 07:57:502831
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492832# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292833def _CheckAndroidToastUsage(input_api, output_api):
2834 """Checks that code uses org.chromium.ui.widget.Toast instead of
2835 android.widget.Toast (Chromium Toast doesn't force hardware
2836 acceleration on low-end devices, saving memory).
2837 """
2838 toast_import_pattern = input_api.re.compile(
2839 r'^import android\.widget\.Toast;$')
2840
2841 errors = []
2842
2843 sources = lambda affected_file: input_api.FilterSourceFile(
2844 affected_file,
2845 black_list=(_EXCLUDED_PATHS +
2846 _TEST_CODE_EXCLUDED_PATHS +
2847 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042848 (r'^chromecast[\\/].*',
2849 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492850 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292851
2852 for f in input_api.AffectedSourceFiles(sources):
2853 for line_num, line in f.ChangedContents():
2854 if toast_import_pattern.search(line):
2855 errors.append("%s:%d" % (f.LocalPath(), line_num))
2856
2857 results = []
2858
2859 if errors:
2860 results.append(output_api.PresubmitError(
2861 'android.widget.Toast usage is detected. Android toasts use hardware'
2862 ' acceleration, and can be\ncostly on low-end devices. Please use'
2863 ' org.chromium.ui.widget.Toast instead.\n'
2864 'Contact [email protected] if you have any questions.',
2865 errors))
2866
2867 return results
2868
2869
dgnaa68d5e2015-06-10 10:08:222870def _CheckAndroidCrLogUsage(input_api, output_api):
2871 """Checks that new logs using org.chromium.base.Log:
2872 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512873 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222874 """
pkotwicza1dd0b002016-05-16 14:41:042875
torne89540622017-03-24 19:41:302876 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042877 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302878 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042879 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302880 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042881 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2882 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092883 # The customtabs_benchmark is a small app that does not depend on Chromium
2884 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042885 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042886 ]
2887
dgnaa68d5e2015-06-10 10:08:222888 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122889 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2890 class_in_base_pattern = input_api.re.compile(
2891 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2892 has_some_log_import_pattern = input_api.re.compile(
2893 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222894 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122895 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222896 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512897 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222898 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222899
Vincent Scheib16d7b272015-09-15 18:09:072900 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222901 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492902 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042903 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122904
dgnaa68d5e2015-06-10 10:08:222905 tag_decl_errors = []
2906 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122907 tag_errors = []
dgn38736db2015-09-18 19:20:512908 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122909 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222910
2911 for f in input_api.AffectedSourceFiles(sources):
2912 file_content = input_api.ReadFile(f)
2913 has_modified_logs = False
2914
2915 # Per line checks
dgn87d9fb62015-06-12 09:15:122916 if (cr_log_import_pattern.search(file_content) or
2917 (class_in_base_pattern.search(file_content) and
2918 not has_some_log_import_pattern.search(file_content))):
2919 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222920 for line_num, line in f.ChangedContents():
2921
2922 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122923 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222924 if match:
2925 has_modified_logs = True
2926
2927 # Make sure it uses "TAG"
2928 if not match.group('tag') == 'TAG':
2929 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122930 else:
2931 # Report non cr Log function calls in changed lines
2932 for line_num, line in f.ChangedContents():
2933 if log_call_pattern.search(line):
2934 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222935
2936 # Per file checks
2937 if has_modified_logs:
2938 # Make sure the tag is using the "cr" prefix and is not too long
2939 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512940 tag_name = match.group('name') if match else None
2941 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222942 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512943 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222944 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512945 elif '.' in tag_name:
2946 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222947
2948 results = []
2949 if tag_decl_errors:
2950 results.append(output_api.PresubmitPromptWarning(
2951 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512952 '"private static final String TAG = "<package tag>".\n'
2953 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222954 tag_decl_errors))
2955
2956 if tag_length_errors:
2957 results.append(output_api.PresubmitError(
2958 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512959 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222960 tag_length_errors))
2961
2962 if tag_errors:
2963 results.append(output_api.PresubmitPromptWarning(
2964 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2965 tag_errors))
2966
dgn87d9fb62015-06-12 09:15:122967 if util_log_errors:
dgn4401aa52015-04-29 16:26:172968 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122969 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2970 util_log_errors))
2971
dgn38736db2015-09-18 19:20:512972 if tag_with_dot_errors:
2973 results.append(output_api.PresubmitPromptWarning(
2974 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2975 tag_with_dot_errors))
2976
dgn4401aa52015-04-29 16:26:172977 return results
2978
2979
Yoland Yanb92fa522017-08-28 17:37:062980def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2981 """Checks that junit.framework.* is no longer used."""
2982 deprecated_junit_framework_pattern = input_api.re.compile(
2983 r'^import junit\.framework\..*;',
2984 input_api.re.MULTILINE)
2985 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492986 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062987 errors = []
2988 for f in input_api.AffectedFiles(sources):
2989 for line_num, line in f.ChangedContents():
2990 if deprecated_junit_framework_pattern.search(line):
2991 errors.append("%s:%d" % (f.LocalPath(), line_num))
2992
2993 results = []
2994 if errors:
2995 results.append(output_api.PresubmitError(
2996 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2997 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2998 ' if you have any question.', errors))
2999 return results
3000
3001
3002def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3003 """Checks that if new Java test classes have inheritance.
3004 Either the new test class is JUnit3 test or it is a JUnit4 test class
3005 with a base class, either case is undesirable.
3006 """
3007 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3008
3009 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493010 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063011 errors = []
3012 for f in input_api.AffectedFiles(sources):
3013 if not f.OldContents():
3014 class_declaration_start_flag = False
3015 for line_num, line in f.ChangedContents():
3016 if class_declaration_pattern.search(line):
3017 class_declaration_start_flag = True
3018 if class_declaration_start_flag and ' extends ' in line:
3019 errors.append('%s:%d' % (f.LocalPath(), line_num))
3020 if '{' in line:
3021 class_declaration_start_flag = False
3022
3023 results = []
3024 if errors:
3025 results.append(output_api.PresubmitPromptWarning(
3026 'The newly created files include Test classes that inherits from base'
3027 ' class. Please do not use inheritance in JUnit4 tests or add new'
3028 ' JUnit3 tests. Contact [email protected] if you have any'
3029 ' questions.', errors))
3030 return results
3031
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203032
yolandyan45001472016-12-21 21:12:423033def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3034 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3035 deprecated_annotation_import_pattern = input_api.re.compile(
3036 r'^import android\.test\.suitebuilder\.annotation\..*;',
3037 input_api.re.MULTILINE)
3038 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493039 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423040 errors = []
3041 for f in input_api.AffectedFiles(sources):
3042 for line_num, line in f.ChangedContents():
3043 if deprecated_annotation_import_pattern.search(line):
3044 errors.append("%s:%d" % (f.LocalPath(), line_num))
3045
3046 results = []
3047 if errors:
3048 results.append(output_api.PresubmitError(
3049 'Annotations in android.test.suitebuilder.annotation have been'
3050 ' deprecated since API level 24. Please use android.support.test.filters'
3051 ' from //third_party/android_support_test_runner:runner_java instead.'
3052 ' Contact [email protected] if you have any questions.', errors))
3053 return results
3054
3055
agrieve7b6479d82015-10-07 14:24:223056def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3057 """Checks if MDPI assets are placed in a correct directory."""
3058 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3059 ('/res/drawable/' in f.LocalPath() or
3060 '/res/drawable-ldrtl/' in f.LocalPath()))
3061 errors = []
3062 for f in input_api.AffectedFiles(include_deletes=False,
3063 file_filter=file_filter):
3064 errors.append(' %s' % f.LocalPath())
3065
3066 results = []
3067 if errors:
3068 results.append(output_api.PresubmitError(
3069 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3070 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3071 '/res/drawable-ldrtl/.\n'
3072 'Contact [email protected] if you have questions.', errors))
3073 return results
3074
3075
Nate Fischer535972b2017-09-16 01:06:183076def _CheckAndroidWebkitImports(input_api, output_api):
3077 """Checks that code uses org.chromium.base.Callback instead of
3078 android.widget.ValueCallback except in the WebView glue layer.
3079 """
3080 valuecallback_import_pattern = input_api.re.compile(
3081 r'^import android\.webkit\.ValueCallback;$')
3082
3083 errors = []
3084
3085 sources = lambda affected_file: input_api.FilterSourceFile(
3086 affected_file,
3087 black_list=(_EXCLUDED_PATHS +
3088 _TEST_CODE_EXCLUDED_PATHS +
3089 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043090 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493091 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183092
3093 for f in input_api.AffectedSourceFiles(sources):
3094 for line_num, line in f.ChangedContents():
3095 if valuecallback_import_pattern.search(line):
3096 errors.append("%s:%d" % (f.LocalPath(), line_num))
3097
3098 results = []
3099
3100 if errors:
3101 results.append(output_api.PresubmitError(
3102 'android.webkit.ValueCallback usage is detected outside of the glue'
3103 ' layer. To stay compatible with the support library, android.webkit.*'
3104 ' classes should only be used inside the glue layer and'
3105 ' org.chromium.base.Callback should be used instead.',
3106 errors))
3107
3108 return results
3109
3110
Becky Zhou7c69b50992018-12-10 19:37:573111def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3112 """Checks Android XML styles """
3113 import sys
3114 original_sys_path = sys.path
3115 try:
3116 sys.path = sys.path + [input_api.os_path.join(
3117 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3118 import checkxmlstyle
3119 finally:
3120 # Restore sys.path to what it was before.
3121 sys.path = original_sys_path
3122
3123 if is_check_on_upload:
3124 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3125 else:
3126 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3127
3128
agrievef32bcc72016-04-04 14:57:403129class PydepsChecker(object):
3130 def __init__(self, input_api, pydeps_files):
3131 self._file_cache = {}
3132 self._input_api = input_api
3133 self._pydeps_files = pydeps_files
3134
3135 def _LoadFile(self, path):
3136 """Returns the list of paths within a .pydeps file relative to //."""
3137 if path not in self._file_cache:
3138 with open(path) as f:
3139 self._file_cache[path] = f.read()
3140 return self._file_cache[path]
3141
3142 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3143 """Returns an interable of paths within the .pydep, relativized to //."""
3144 os_path = self._input_api.os_path
3145 pydeps_dir = os_path.dirname(pydeps_path)
3146 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3147 if not l.startswith('*'))
3148 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3149
3150 def _CreateFilesToPydepsMap(self):
3151 """Returns a map of local_path -> list_of_pydeps."""
3152 ret = {}
3153 for pydep_local_path in self._pydeps_files:
3154 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3155 ret.setdefault(path, []).append(pydep_local_path)
3156 return ret
3157
3158 def ComputeAffectedPydeps(self):
3159 """Returns an iterable of .pydeps files that might need regenerating."""
3160 affected_pydeps = set()
3161 file_to_pydeps_map = None
3162 for f in self._input_api.AffectedFiles(include_deletes=True):
3163 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463164 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3165 # subrepositories. We can't figure out which files change, so re-check
3166 # all files.
3167 # Changes to print_python_deps.py affect all .pydeps.
3168 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403169 return self._pydeps_files
3170 elif local_path.endswith('.pydeps'):
3171 if local_path in self._pydeps_files:
3172 affected_pydeps.add(local_path)
3173 elif local_path.endswith('.py'):
3174 if file_to_pydeps_map is None:
3175 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3176 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3177 return affected_pydeps
3178
3179 def DetermineIfStale(self, pydeps_path):
3180 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413181 import difflib
John Budorick47ca3fe2018-02-10 00:53:103182 import os
3183
agrievef32bcc72016-04-04 14:57:403184 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3185 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103186 env = dict(os.environ)
3187 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403188 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103189 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413190 old_contents = old_pydeps_data[2:]
3191 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403192 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413193 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403194
3195
3196def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3197 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403198 # This check is for Python dependency lists (.pydeps files), and involves
3199 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3200 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283201 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003202 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:023203 # TODO(agrieve): Update when there's a better way to detect
3204 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:403205 is_android = input_api.os_path.exists('third_party/android_tools')
3206 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3207 results = []
3208 # First, check for new / deleted .pydeps.
3209 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033210 # Check whether we are running the presubmit check for a file in src.
3211 # f.LocalPath is relative to repo (src, or internal repo).
3212 # os_path.exists is relative to src repo.
3213 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3214 # to src and we can conclude that the pydeps is in src.
3215 if input_api.os_path.exists(f.LocalPath()):
3216 if f.LocalPath().endswith('.pydeps'):
3217 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3218 results.append(output_api.PresubmitError(
3219 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3220 'remove %s' % f.LocalPath()))
3221 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3222 results.append(output_api.PresubmitError(
3223 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3224 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403225
3226 if results:
3227 return results
3228
3229 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3230
3231 for pydep_path in checker.ComputeAffectedPydeps():
3232 try:
phajdan.jr0d9878552016-11-04 10:49:413233 result = checker.DetermineIfStale(pydep_path)
3234 if result:
3235 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403236 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413237 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3238 'To regenerate, run:\n\n %s' %
3239 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403240 except input_api.subprocess.CalledProcessError as error:
3241 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3242 long_text=error.output)]
3243
3244 return results
3245
3246
glidere61efad2015-02-18 17:39:433247def _CheckSingletonInHeaders(input_api, output_api):
3248 """Checks to make sure no header files have |Singleton<|."""
3249 def FileFilter(affected_file):
3250 # It's ok for base/memory/singleton.h to have |Singleton<|.
3251 black_list = (_EXCLUDED_PATHS +
3252 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043253 (r"^base[\\/]memory[\\/]singleton\.h$",
3254 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473255 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433256 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3257
sergeyu34d21222015-09-16 00:11:443258 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433259 files = []
3260 for f in input_api.AffectedSourceFiles(FileFilter):
3261 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3262 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3263 contents = input_api.ReadFile(f)
3264 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243265 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433266 pattern.search(line)):
3267 files.append(f)
3268 break
3269
3270 if files:
yolandyandaabc6d2016-04-18 18:29:393271 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443272 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433273 'Please move them to an appropriate source file so that the ' +
3274 'template gets instantiated in a single compilation unit.',
3275 files) ]
3276 return []
3277
3278
[email protected]fd20b902014-05-09 02:14:533279_DEPRECATED_CSS = [
3280 # Values
3281 ( "-webkit-box", "flex" ),
3282 ( "-webkit-inline-box", "inline-flex" ),
3283 ( "-webkit-flex", "flex" ),
3284 ( "-webkit-inline-flex", "inline-flex" ),
3285 ( "-webkit-min-content", "min-content" ),
3286 ( "-webkit-max-content", "max-content" ),
3287
3288 # Properties
3289 ( "-webkit-background-clip", "background-clip" ),
3290 ( "-webkit-background-origin", "background-origin" ),
3291 ( "-webkit-background-size", "background-size" ),
3292 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443293 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533294
3295 # Functions
3296 ( "-webkit-gradient", "gradient" ),
3297 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3298 ( "-webkit-linear-gradient", "linear-gradient" ),
3299 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3300 ( "-webkit-radial-gradient", "radial-gradient" ),
3301 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3302]
3303
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203304
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493305# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243306def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533307 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253308 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343309 documentation and iOS CSS for dom distiller
3310 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253311 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533312 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493313 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253314 black_list = (_EXCLUDED_PATHS +
3315 _TEST_CODE_EXCLUDED_PATHS +
3316 input_api.DEFAULT_BLACK_LIST +
3317 (r"^chrome/common/extensions/docs",
3318 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343319 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443320 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253321 r"^native_client_sdk"))
3322 file_filter = lambda f: input_api.FilterSourceFile(
3323 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533324 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3325 for line_num, line in fpath.ChangedContents():
3326 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023327 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533328 results.append(output_api.PresubmitError(
3329 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3330 (fpath.LocalPath(), line_num, deprecated_value, value)))
3331 return results
3332
mohan.reddyf21db962014-10-16 12:26:473333
dbeam070cfe62014-10-22 06:44:023334_DEPRECATED_JS = [
3335 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
3336 ( "__defineGetter__", "Object.defineProperty" ),
3337 ( "__defineSetter__", "Object.defineProperty" ),
3338]
3339
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203340
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493341# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243342def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:023343 """Make sure that we don't use deprecated JS in Chrome code."""
3344 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493345 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:023346 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3347 input_api.DEFAULT_BLACK_LIST)
3348 file_filter = lambda f: input_api.FilterSourceFile(
3349 f, white_list=file_inclusion_pattern, black_list=black_list)
3350 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3351 for lnum, line in fpath.ChangedContents():
3352 for (deprecated, replacement) in _DEPRECATED_JS:
3353 if deprecated in line:
3354 results.append(output_api.PresubmitError(
3355 "%s:%d: Use of deprecated JS %s, use %s instead" %
3356 (fpath.LocalPath(), lnum, deprecated, replacement)))
3357 return results
3358
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203359
rlanday6802cf632017-05-30 17:48:363360def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363361 bad_files = {}
3362 for f in input_api.AffectedFiles(include_deletes=False):
3363 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493364 not f.LocalPath().startswith('third_party/blink') and
3365 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363366 continue
3367
Daniel Bratell65b033262019-04-23 08:17:063368 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363369 continue
3370
Vaclav Brozekd5de76a2018-03-17 07:57:503371 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363372 if "#include" in line and "../" in line]
3373 if not relative_includes:
3374 continue
3375 bad_files[f.LocalPath()] = relative_includes
3376
3377 if not bad_files:
3378 return []
3379
3380 error_descriptions = []
3381 for file_path, bad_lines in bad_files.iteritems():
3382 error_description = file_path
3383 for line in bad_lines:
3384 error_description += '\n ' + line
3385 error_descriptions.append(error_description)
3386
3387 results = []
3388 results.append(output_api.PresubmitError(
3389 'You added one or more relative #include paths (including "../").\n'
3390 'These shouldn\'t be used because they can be used to include headers\n'
3391 'from code that\'s not correctly specified as a dependency in the\n'
3392 'relevant BUILD.gn file(s).',
3393 error_descriptions))
3394
3395 return results
3396
Takeshi Yoshinoe387aa32017-08-02 13:16:133397
Daniel Bratell65b033262019-04-23 08:17:063398def _CheckForCcIncludes(input_api, output_api):
3399 """Check that nobody tries to include a cc file. It's a relatively
3400 common error which results in duplicate symbols in object
3401 files. This may not always break the build until someone later gets
3402 very confusing linking errors."""
3403 results = []
3404 for f in input_api.AffectedFiles(include_deletes=False):
3405 # We let third_party code do whatever it wants
3406 if (f.LocalPath().startswith('third_party') and
3407 not f.LocalPath().startswith('third_party/blink') and
3408 not f.LocalPath().startswith('third_party\\blink')):
3409 continue
3410
3411 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3412 continue
3413
3414 for _, line in f.ChangedContents():
3415 if line.startswith('#include "'):
3416 included_file = line.split('"')[1]
3417 if _IsCPlusPlusFile(input_api, included_file):
3418 # The most common naming for external files with C++ code,
3419 # apart from standard headers, is to call them foo.inc, but
3420 # Chromium sometimes uses foo-inc.cc so allow that as well.
3421 if not included_file.endswith(('.h', '-inc.cc')):
3422 results.append(output_api.PresubmitError(
3423 'Only header files or .inc files should be included in other\n'
3424 'C++ files. Compiling the contents of a cc file more than once\n'
3425 'will cause duplicate information in the build which may later\n'
3426 'result in strange link_errors.\n' +
3427 f.LocalPath() + ':\n ' +
3428 line))
3429
3430 return results
3431
3432
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203433def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3434 if not isinstance(key, ast.Str):
3435 return 'Key at line %d must be a string literal' % key.lineno
3436 if not isinstance(value, ast.Dict):
3437 return 'Value at line %d must be a dict' % value.lineno
3438 if len(value.keys) != 1:
3439 return 'Dict at line %d must have single entry' % value.lineno
3440 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3441 return (
3442 'Entry at line %d must have a string literal \'filepath\' as key' %
3443 value.lineno)
3444 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133445
Takeshi Yoshinoe387aa32017-08-02 13:16:133446
Sergey Ulanov4af16052018-11-08 02:41:463447def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203448 if not isinstance(key, ast.Str):
3449 return 'Key at line %d must be a string literal' % key.lineno
3450 if not isinstance(value, ast.List):
3451 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463452 for element in value.elts:
3453 if not isinstance(element, ast.Str):
3454 return 'Watchlist elements on line %d is not a string' % key.lineno
3455 if not email_regex.match(element.s):
3456 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3457 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203458 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133459
Takeshi Yoshinoe387aa32017-08-02 13:16:133460
Sergey Ulanov4af16052018-11-08 02:41:463461def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203462 mismatch_template = (
3463 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3464 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133465
Sergey Ulanov4af16052018-11-08 02:41:463466 email_regex = input_api.re.compile(
3467 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3468
3469 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203470 i = 0
3471 last_key = ''
3472 while True:
3473 if i >= len(wd_dict.keys):
3474 if i >= len(w_dict.keys):
3475 return None
3476 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3477 elif i >= len(w_dict.keys):
3478 return (
3479 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133480
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203481 wd_key = wd_dict.keys[i]
3482 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133483
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203484 result = _CheckWatchlistDefinitionsEntrySyntax(
3485 wd_key, wd_dict.values[i], ast)
3486 if result is not None:
3487 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133488
Sergey Ulanov4af16052018-11-08 02:41:463489 result = _CheckWatchlistsEntrySyntax(
3490 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203491 if result is not None:
3492 return 'Bad entry in WATCHLISTS dict: %s' % result
3493
3494 if wd_key.s != w_key.s:
3495 return mismatch_template % (
3496 '%s at line %d' % (wd_key.s, wd_key.lineno),
3497 '%s at line %d' % (w_key.s, w_key.lineno))
3498
3499 if wd_key.s < last_key:
3500 return (
3501 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3502 (wd_key.lineno, w_key.lineno))
3503 last_key = wd_key.s
3504
3505 i = i + 1
3506
3507
Sergey Ulanov4af16052018-11-08 02:41:463508def _CheckWATCHLISTSSyntax(expression, input_api):
3509 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203510 if not isinstance(expression, ast.Expression):
3511 return 'WATCHLISTS file must contain a valid expression'
3512 dictionary = expression.body
3513 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3514 return 'WATCHLISTS file must have single dict with exactly two entries'
3515
3516 first_key = dictionary.keys[0]
3517 first_value = dictionary.values[0]
3518 second_key = dictionary.keys[1]
3519 second_value = dictionary.values[1]
3520
3521 if (not isinstance(first_key, ast.Str) or
3522 first_key.s != 'WATCHLIST_DEFINITIONS' or
3523 not isinstance(first_value, ast.Dict)):
3524 return (
3525 'The first entry of the dict in WATCHLISTS file must be '
3526 'WATCHLIST_DEFINITIONS dict')
3527
3528 if (not isinstance(second_key, ast.Str) or
3529 second_key.s != 'WATCHLISTS' or
3530 not isinstance(second_value, ast.Dict)):
3531 return (
3532 'The second entry of the dict in WATCHLISTS file must be '
3533 'WATCHLISTS dict')
3534
Sergey Ulanov4af16052018-11-08 02:41:463535 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133536
3537
3538def _CheckWATCHLISTS(input_api, output_api):
3539 for f in input_api.AffectedFiles(include_deletes=False):
3540 if f.LocalPath() == 'WATCHLISTS':
3541 contents = input_api.ReadFile(f, 'r')
3542
3543 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203544 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133545 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203546 # Get an AST tree for it and scan the tree for detailed style checking.
3547 expression = input_api.ast.parse(
3548 contents, filename='WATCHLISTS', mode='eval')
3549 except ValueError as e:
3550 return [output_api.PresubmitError(
3551 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3552 except SyntaxError as e:
3553 return [output_api.PresubmitError(
3554 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3555 except TypeError as e:
3556 return [output_api.PresubmitError(
3557 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133558
Sergey Ulanov4af16052018-11-08 02:41:463559 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203560 if result is not None:
3561 return [output_api.PresubmitError(result)]
3562 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133563
3564 return []
3565
3566
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193567def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3568 """Checks that newly added header files have corresponding GN changes.
3569 Note that this is only a heuristic. To be precise, run script:
3570 build/check_gn_headers.py.
3571 """
3572
3573 def headers(f):
3574 return input_api.FilterSourceFile(
3575 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3576
3577 new_headers = []
3578 for f in input_api.AffectedSourceFiles(headers):
3579 if f.Action() != 'A':
3580 continue
3581 new_headers.append(f.LocalPath())
3582
3583 def gn_files(f):
3584 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3585
3586 all_gn_changed_contents = ''
3587 for f in input_api.AffectedSourceFiles(gn_files):
3588 for _, line in f.ChangedContents():
3589 all_gn_changed_contents += line
3590
3591 problems = []
3592 for header in new_headers:
3593 basename = input_api.os_path.basename(header)
3594 if basename not in all_gn_changed_contents:
3595 problems.append(header)
3596
3597 if problems:
3598 return [output_api.PresubmitPromptWarning(
3599 'Missing GN changes for new header files', items=sorted(problems),
3600 long_text='Please double check whether newly added header files need '
3601 'corresponding changes in gn or gni files.\nThis checking is only a '
3602 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3603 'Read https://crbug.com/661774 for more info.')]
3604 return []
3605
3606
Michael Giuffridad3bc8672018-10-25 22:48:023607def _CheckCorrectProductNameInMessages(input_api, output_api):
3608 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3609
3610 This assumes we won't intentionally reference one product from the other
3611 product.
3612 """
3613 all_problems = []
3614 test_cases = [{
3615 "filename_postfix": "google_chrome_strings.grd",
3616 "correct_name": "Chrome",
3617 "incorrect_name": "Chromium",
3618 }, {
3619 "filename_postfix": "chromium_strings.grd",
3620 "correct_name": "Chromium",
3621 "incorrect_name": "Chrome",
3622 }]
3623
3624 for test_case in test_cases:
3625 problems = []
3626 filename_filter = lambda x: x.LocalPath().endswith(
3627 test_case["filename_postfix"])
3628
3629 # Check each new line. Can yield false positives in multiline comments, but
3630 # easier than trying to parse the XML because messages can have nested
3631 # children, and associating message elements with affected lines is hard.
3632 for f in input_api.AffectedSourceFiles(filename_filter):
3633 for line_num, line in f.ChangedContents():
3634 if "<message" in line or "<!--" in line or "-->" in line:
3635 continue
3636 if test_case["incorrect_name"] in line:
3637 problems.append(
3638 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3639
3640 if problems:
3641 message = (
3642 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3643 % (test_case["correct_name"], test_case["correct_name"],
3644 test_case["incorrect_name"]))
3645 all_problems.append(
3646 output_api.PresubmitPromptWarning(message, items=problems))
3647
3648 return all_problems
3649
3650
Dirk Pranke3c18a382019-03-15 01:07:513651def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3652 # TODO(crbug.com/941824): We need to make sure the entries in
3653 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3654 # so that users of //buildtools in other projects get the same tooling
3655 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3656 # support to gclient, we can eliminate the duplication and delete
3657 # this presubmit check.
3658
3659 # Update this regexp if new revisions are added to the files.
3660 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013661 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513662
3663 # If a user is changing one revision, they need to change the same
3664 # line in both files. This means that any given change should contain
3665 # exactly the same list of changed lines that match the regexps. The
3666 # replace(' ', '') call allows us to ignore whitespace changes to the
3667 # lines. The 'long_text' parameter to the error will contain the
3668 # list of changed lines in both files, which should make it easy enough
3669 # to spot the error without going overboard in this implementation.
3670 revs_changes = {
3671 'DEPS': {},
3672 'buildtools/DEPS': {},
3673 }
3674 long_text = ''
3675
3676 for f in input_api.AffectedFiles(
3677 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3678 for line_num, line in f.ChangedContents():
3679 if rev_regexp.search(line):
3680 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3681 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3682
3683 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3684 return [output_api.PresubmitError(
3685 'Change buildtools revisions in sync in both //DEPS and '
3686 '//buildtools/DEPS.', long_text=long_text + '\n')]
3687 else:
3688 return []
3689
3690
Daniel Bratell93eb6c62019-04-29 20:13:363691def _CheckForTooLargeFiles(input_api, output_api):
3692 """Avoid large files, especially binary files, in the repository since
3693 git doesn't scale well for those. They will be in everyone's repo
3694 clones forever, forever making Chromium slower to clone and work
3695 with."""
3696
3697 # Uploading files to cloud storage is not trivial so we don't want
3698 # to set the limit too low, but the upper limit for "normal" large
3699 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3700 # anything over 20 MB is exceptional.
3701 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3702
3703 too_large_files = []
3704 for f in input_api.AffectedFiles():
3705 # Check both added and modified files (but not deleted files).
3706 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383707 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363708 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3709 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3710
3711 if too_large_files:
3712 message = (
3713 'Do not commit large files to git since git scales badly for those.\n' +
3714 'Instead put the large files in cloud storage and use DEPS to\n' +
3715 'fetch them.\n' + '\n'.join(too_large_files)
3716 )
3717 return [output_api.PresubmitError(
3718 'Too large files found in commit', long_text=message + '\n')]
3719 else:
3720 return []
3721
dgnaa68d5e2015-06-10 10:08:223722def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573723 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223724 results = []
dgnaa68d5e2015-06-10 10:08:223725 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173726 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223727 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293728 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063729 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3730 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423731 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183732 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573733 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3734 return results
3735
3736def _AndroidSpecificOnCommitChecks(input_api, output_api):
3737 """Groups commit checks that target android code."""
3738 results = []
3739 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223740 return results
3741
3742
[email protected]22c9bd72011-03-27 16:47:393743def _CommonChecks(input_api, output_api):
3744 """Checks common to both upload and commit."""
3745 results = []
3746 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383747 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543748 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083749
3750 author = input_api.change.author_email
3751 if author and author not in _KNOWN_ROBOTS:
3752 results.extend(
3753 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3754
[email protected]55459852011-08-10 15:17:193755 results.extend(
[email protected]760deea2013-12-10 19:33:493756 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233757 results.extend(
3758 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543759 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183760 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343761 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523762 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223763 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443764 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593765 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063766 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123767 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183768 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223769 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303770 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493771 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033772 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493773 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443774 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273775 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073776 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543777 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443778 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393779 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553780 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043781 results.extend(
3782 input_api.canned_checks.CheckChangeHasNoTabs(
3783 input_api,
3784 output_api,
3785 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403786 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163787 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083788 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243789 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3790 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473791 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043792 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053793 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143794 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233795 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433796 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403797 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153798 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173799 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503800 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363801 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063802 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133803 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433804 results.extend(input_api.RunTests(
3805 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143806 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023807 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513808 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:363809 results.extend(_CheckForTooLargeFiles(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243810
Vaclav Brozekcdc7defb2018-03-20 09:54:353811 for f in input_api.AffectedFiles():
3812 path, name = input_api.os_path.split(f.LocalPath())
3813 if name == 'PRESUBMIT.py':
3814 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003815 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3816 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073817 # The PRESUBMIT.py file (and the directory containing it) might
3818 # have been affected by being moved or removed, so only try to
3819 # run the tests if they still exist.
3820 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3821 input_api, output_api, full_path,
3822 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393823 return results
[email protected]1f7b4172010-01-28 01:17:343824
[email protected]b337cb5b2011-01-23 21:24:053825
[email protected]b8079ae4a2012-12-05 19:56:493826def _CheckPatchFiles(input_api, output_api):
3827 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3828 if f.LocalPath().endswith(('.orig', '.rej'))]
3829 if problems:
3830 return [output_api.PresubmitError(
3831 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033832 else:
3833 return []
[email protected]b8079ae4a2012-12-05 19:56:493834
3835
Kent Tamura5a8755d2017-06-29 23:37:073836def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213837 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3838 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3839 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073840 include_re = input_api.re.compile(
3841 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3842 extension_re = input_api.re.compile(r'\.[a-z]+$')
3843 errors = []
3844 for f in input_api.AffectedFiles():
3845 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3846 continue
3847 found_line_number = None
3848 found_macro = None
3849 for line_num, line in f.ChangedContents():
3850 match = macro_re.search(line)
3851 if match:
3852 found_line_number = line_num
3853 found_macro = match.group(2)
3854 break
3855 if not found_line_number:
3856 continue
3857
3858 found_include = False
3859 for line in f.NewContents():
3860 if include_re.search(line):
3861 found_include = True
3862 break
3863 if found_include:
3864 continue
3865
3866 if not f.LocalPath().endswith('.h'):
3867 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3868 try:
3869 content = input_api.ReadFile(primary_header_path, 'r')
3870 if include_re.search(content):
3871 continue
3872 except IOError:
3873 pass
3874 errors.append('%s:%d %s macro is used without including build/'
3875 'build_config.h.'
3876 % (f.LocalPath(), found_line_number, found_macro))
3877 if errors:
3878 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3879 return []
3880
3881
[email protected]b00342e7f2013-03-26 16:21:543882def _DidYouMeanOSMacro(bad_macro):
3883 try:
3884 return {'A': 'OS_ANDROID',
3885 'B': 'OS_BSD',
3886 'C': 'OS_CHROMEOS',
3887 'F': 'OS_FREEBSD',
3888 'L': 'OS_LINUX',
3889 'M': 'OS_MACOSX',
3890 'N': 'OS_NACL',
3891 'O': 'OS_OPENBSD',
3892 'P': 'OS_POSIX',
3893 'S': 'OS_SOLARIS',
3894 'W': 'OS_WIN'}[bad_macro[3].upper()]
3895 except KeyError:
3896 return ''
3897
3898
3899def _CheckForInvalidOSMacrosInFile(input_api, f):
3900 """Check for sensible looking, totally invalid OS macros."""
3901 preprocessor_statement = input_api.re.compile(r'^\s*#')
3902 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3903 results = []
3904 for lnum, line in f.ChangedContents():
3905 if preprocessor_statement.search(line):
3906 for match in os_macro.finditer(line):
3907 if not match.group(1) in _VALID_OS_MACROS:
3908 good = _DidYouMeanOSMacro(match.group(1))
3909 did_you_mean = ' (did you mean %s?)' % good if good else ''
3910 results.append(' %s:%d %s%s' % (f.LocalPath(),
3911 lnum,
3912 match.group(1),
3913 did_you_mean))
3914 return results
3915
3916
3917def _CheckForInvalidOSMacros(input_api, output_api):
3918 """Check all affected files for invalid OS macros."""
3919 bad_macros = []
tzik3f295992018-12-04 20:32:233920 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473921 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543922 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3923
3924 if not bad_macros:
3925 return []
3926
3927 return [output_api.PresubmitError(
3928 'Possibly invalid OS macro[s] found. Please fix your code\n'
3929 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3930
lliabraa35bab3932014-10-01 12:16:443931
3932def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3933 """Check all affected files for invalid "if defined" macros."""
3934 ALWAYS_DEFINED_MACROS = (
3935 "TARGET_CPU_PPC",
3936 "TARGET_CPU_PPC64",
3937 "TARGET_CPU_68K",
3938 "TARGET_CPU_X86",
3939 "TARGET_CPU_ARM",
3940 "TARGET_CPU_MIPS",
3941 "TARGET_CPU_SPARC",
3942 "TARGET_CPU_ALPHA",
3943 "TARGET_IPHONE_SIMULATOR",
3944 "TARGET_OS_EMBEDDED",
3945 "TARGET_OS_IPHONE",
3946 "TARGET_OS_MAC",
3947 "TARGET_OS_UNIX",
3948 "TARGET_OS_WIN32",
3949 )
3950 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3951 results = []
3952 for lnum, line in f.ChangedContents():
3953 for match in ifdef_macro.finditer(line):
3954 if match.group(1) in ALWAYS_DEFINED_MACROS:
3955 always_defined = ' %s is always defined. ' % match.group(1)
3956 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3957 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3958 lnum,
3959 always_defined,
3960 did_you_mean))
3961 return results
3962
3963
3964def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3965 """Check all affected files for invalid "if defined" macros."""
3966 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:053967 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:443968 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:053969 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:213970 continue
lliabraa35bab3932014-10-01 12:16:443971 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3972 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3973
3974 if not bad_macros:
3975 return []
3976
3977 return [output_api.PresubmitError(
3978 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3979 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3980 bad_macros)]
3981
3982
mlamouria82272622014-09-16 18:45:043983def _CheckForIPCRules(input_api, output_api):
3984 """Check for same IPC rules described in
3985 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3986 """
3987 base_pattern = r'IPC_ENUM_TRAITS\('
3988 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3989 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3990
3991 problems = []
3992 for f in input_api.AffectedSourceFiles(None):
3993 local_path = f.LocalPath()
3994 if not local_path.endswith('.h'):
3995 continue
3996 for line_number, line in f.ChangedContents():
3997 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3998 problems.append(
3999 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4000
4001 if problems:
4002 return [output_api.PresubmitPromptWarning(
4003 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4004 else:
4005 return []
4006
[email protected]b00342e7f2013-03-26 16:21:544007
Stephen Martinis97a394142018-06-07 23:06:054008def _CheckForLongPathnames(input_api, output_api):
4009 """Check to make sure no files being submitted have long paths.
4010 This causes issues on Windows.
4011 """
4012 problems = []
4013 for f in input_api.AffectedSourceFiles(None):
4014 local_path = f.LocalPath()
4015 # Windows has a path limit of 260 characters. Limit path length to 200 so
4016 # that we have some extra for the prefix on dev machines and the bots.
4017 if len(local_path) > 200:
4018 problems.append(local_path)
4019
4020 if problems:
4021 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4022 else:
4023 return []
4024
4025
Daniel Bratell8ba52722018-03-02 16:06:144026def _CheckForIncludeGuards(input_api, output_api):
4027 """Check that header files have proper guards against multiple inclusion.
4028 If a file should not have such guards (and it probably should) then it
4029 should include the string "no-include-guard-because-multiply-included".
4030 """
Daniel Bratell6a75baef62018-06-04 10:04:454031 def is_chromium_header_file(f):
4032 # We only check header files under the control of the Chromium
4033 # project. That is, those outside third_party apart from
4034 # third_party/blink.
4035 file_with_path = input_api.os_path.normpath(f.LocalPath())
4036 return (file_with_path.endswith('.h') and
4037 (not file_with_path.startswith('third_party') or
4038 file_with_path.startswith(
4039 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144040
4041 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344042 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144043
4044 errors = []
4045
Daniel Bratell6a75baef62018-06-04 10:04:454046 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144047 guard_name = None
4048 guard_line_number = None
4049 seen_guard_end = False
4050
4051 file_with_path = input_api.os_path.normpath(f.LocalPath())
4052 base_file_name = input_api.os_path.splitext(
4053 input_api.os_path.basename(file_with_path))[0]
4054 upper_base_file_name = base_file_name.upper()
4055
4056 expected_guard = replace_special_with_underscore(
4057 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144058
4059 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574060 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4061 # are too many (1000+) files with slight deviations from the
4062 # coding style. The most important part is that the include guard
4063 # is there, and that it's unique, not the name so this check is
4064 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144065 #
4066 # As code becomes more uniform, this could be made stricter.
4067
4068 guard_name_pattern_list = [
4069 # Anything with the right suffix (maybe with an extra _).
4070 r'\w+_H__?',
4071
Daniel Bratell39b5b062018-05-16 18:09:574072 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144073 r'\w+_h',
4074
4075 # Anything including the uppercase name of the file.
4076 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4077 upper_base_file_name)) + r'\w*',
4078 ]
4079 guard_name_pattern = '|'.join(guard_name_pattern_list)
4080 guard_pattern = input_api.re.compile(
4081 r'#ifndef\s+(' + guard_name_pattern + ')')
4082
4083 for line_number, line in enumerate(f.NewContents()):
4084 if 'no-include-guard-because-multiply-included' in line:
4085 guard_name = 'DUMMY' # To not trigger check outside the loop.
4086 break
4087
4088 if guard_name is None:
4089 match = guard_pattern.match(line)
4090 if match:
4091 guard_name = match.group(1)
4092 guard_line_number = line_number
4093
Daniel Bratell39b5b062018-05-16 18:09:574094 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454095 # don't match the chromium style guide, but new files should
4096 # get it right.
4097 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574098 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144099 errors.append(output_api.PresubmitPromptWarning(
4100 'Header using the wrong include guard name %s' % guard_name,
4101 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:574102 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144103 else:
4104 # The line after #ifndef should have a #define of the same name.
4105 if line_number == guard_line_number + 1:
4106 expected_line = '#define %s' % guard_name
4107 if line != expected_line:
4108 errors.append(output_api.PresubmitPromptWarning(
4109 'Missing "%s" for include guard' % expected_line,
4110 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4111 'Expected: %r\nGot: %r' % (expected_line, line)))
4112
4113 if not seen_guard_end and line == '#endif // %s' % guard_name:
4114 seen_guard_end = True
4115 elif seen_guard_end:
4116 if line.strip() != '':
4117 errors.append(output_api.PresubmitPromptWarning(
4118 'Include guard %s not covering the whole file' % (
4119 guard_name), [f.LocalPath()]))
4120 break # Nothing else to check and enough to warn once.
4121
4122 if guard_name is None:
4123 errors.append(output_api.PresubmitPromptWarning(
4124 'Missing include guard %s' % expected_guard,
4125 [f.LocalPath()],
4126 'Missing include guard in %s\n'
4127 'Recommended name: %s\n'
4128 'This check can be disabled by having the string\n'
4129 'no-include-guard-because-multiply-included in the header.' %
4130 (f.LocalPath(), expected_guard)))
4131
4132 return errors
4133
4134
mostynbb639aca52015-01-07 20:31:234135def _CheckForWindowsLineEndings(input_api, output_api):
4136 """Check source code and known ascii text files for Windows style line
4137 endings.
4138 """
earthdok1b5e0ee2015-03-10 15:19:104139 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234140
4141 file_inclusion_pattern = (
4142 known_text_files,
4143 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4144 )
4145
mostynbb639aca52015-01-07 20:31:234146 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534147 source_file_filter = lambda f: input_api.FilterSourceFile(
4148 f, white_list=file_inclusion_pattern, black_list=None)
4149 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504150 include_file = False
4151 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234152 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504153 include_file = True
4154 if include_file:
4155 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234156
4157 if problems:
4158 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4159 'these files to contain Windows style line endings?\n' +
4160 '\n'.join(problems))]
4161
4162 return []
4163
4164
Vaclav Brozekd5de76a2018-03-17 07:57:504165def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134166 """Checks that all source files use SYSLOG properly."""
4167 syslog_files = []
4168 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564169 for line_number, line in f.ChangedContents():
4170 if 'SYSLOG' in line:
4171 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4172
pastarmovj89f7ee12016-09-20 14:58:134173 if syslog_files:
4174 return [output_api.PresubmitPromptWarning(
4175 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4176 ' calls.\nFiles to check:\n', items=syslog_files)]
4177 return []
4178
4179
[email protected]1f7b4172010-01-28 01:17:344180def CheckChangeOnUpload(input_api, output_api):
4181 results = []
4182 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474183 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284184 results.extend(
jam93a6ee792017-02-08 23:59:224185 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194186 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224187 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134188 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164189 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534190 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194191 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544192 return results
[email protected]ca8d19842009-02-19 16:33:124193
4194
[email protected]1bfb8322014-04-23 01:02:414195def GetTryServerMasterForBot(bot):
4196 """Returns the Try Server master for the given bot.
4197
[email protected]0bb112362014-07-26 04:38:324198 It tries to guess the master from the bot name, but may still fail
4199 and return None. There is no longer a default master.
4200 """
4201 # Potentially ambiguous bot names are listed explicitly.
4202 master_map = {
tandriie5587792016-07-14 00:34:504203 'chromium_presubmit': 'master.tryserver.chromium.linux',
4204 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414205 }
[email protected]0bb112362014-07-26 04:38:324206 master = master_map.get(bot)
4207 if not master:
wnwen4fbaab82016-05-25 12:54:364208 if 'android' in bot:
tandriie5587792016-07-14 00:34:504209 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364210 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504211 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324212 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504213 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324214 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504215 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324216 return master
[email protected]1bfb8322014-04-23 01:02:414217
4218
[email protected]ca8d19842009-02-19 16:33:124219def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544220 results = []
[email protected]1f7b4172010-01-28 01:17:344221 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574222 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544223 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274224 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344225 input_api,
4226 output_api,
[email protected]2fdd1f362013-01-16 03:56:034227 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274228
jam93a6ee792017-02-08 23:59:224229 results.extend(
4230 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544231 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4232 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414233 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4234 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544235 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144236
4237
4238def _CheckTranslationScreenshots(input_api, output_api):
4239 PART_FILE_TAG = "part"
4240 import os
4241 import sys
4242 from io import StringIO
4243
4244 try:
4245 old_sys_path = sys.path
4246 sys.path = sys.path + [input_api.os_path.join(
4247 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4248 import grit.grd_reader
4249 import grit.node.message
4250 import grit.util
4251 finally:
4252 sys.path = old_sys_path
4253
4254 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4255 """Load the grd file and return a dict of message ids to messages.
4256
4257 Ignores any nested grdp files pointed by <part> tag.
4258 """
4259 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4260 stop_after=None, first_ids_file=None,
4261 debug=False, defines=None,
4262 tags_to_ignore=set([PART_FILE_TAG]))
4263 return {
4264 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4265 grit.node.message.MessageNode)
4266 }
4267
4268 def _GetGrdpMessagesFromString(grdp_string):
4269 """Parses the contents of a grdp file given in grdp_string.
4270
4271 grd_reader can't parse grdp files directly. Instead, this creates a
4272 temporary directory with a grd file pointing to the grdp file, and loads the
4273 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4274 """
4275 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4276 <grit latest_public_release="1" current_release="1">
4277 <release seq="1">
4278 <messages>
4279 <part file="sub.grdp" />
4280 </messages>
4281 </release>
4282 </grit>
4283 """
4284 with grit.util.TempDir({'main.grd': WRAPPER,
4285 'sub.grdp': grdp_string}) as temp_dir:
4286 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4287
4288 new_or_added_paths = set(f.LocalPath()
4289 for f in input_api.AffectedFiles()
4290 if (f.Action() == 'A' or f.Action() == 'M'))
4291 removed_paths = set(f.LocalPath()
4292 for f in input_api.AffectedFiles(include_deletes=True)
4293 if f.Action() == 'D')
4294
4295 affected_grds = [f for f in input_api.AffectedFiles()
4296 if (f.LocalPath().endswith('.grd') or
4297 f.LocalPath().endswith('.grdp'))]
4298 affected_png_paths = [f.AbsoluteLocalPath()
4299 for f in input_api.AffectedFiles()
4300 if (f.LocalPath().endswith('.png'))]
4301
4302 # Check for screenshots. Developers can upload screenshots using
4303 # tools/translation/upload_screenshots.py which finds and uploads
4304 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4305 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4306 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4307 #
4308 # The logic here is as follows:
4309 #
4310 # - If the CL has a .png file under the screenshots directory for a grd
4311 # file, warn the developer. Actual images should never be checked into the
4312 # Chrome repo.
4313 #
4314 # - If the CL contains modified or new messages in grd files and doesn't
4315 # contain the corresponding .sha1 files, warn the developer to add images
4316 # and upload them via tools/translation/upload_screenshots.py.
4317 #
4318 # - If the CL contains modified or new messages in grd files and the
4319 # corresponding .sha1 files, everything looks good.
4320 #
4321 # - If the CL contains removed messages in grd files but the corresponding
4322 # .sha1 files aren't removed, warn the developer to remove them.
4323 unnecessary_screenshots = []
4324 missing_sha1 = []
4325 unnecessary_sha1_files = []
4326
4327
4328 def _CheckScreenshotAdded(screenshots_dir, message_id):
4329 sha1_path = input_api.os_path.join(
4330 screenshots_dir, message_id + '.png.sha1')
4331 if sha1_path not in new_or_added_paths:
4332 missing_sha1.append(sha1_path)
4333
4334
4335 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4336 sha1_path = input_api.os_path.join(
4337 screenshots_dir, message_id + '.png.sha1')
4338 if sha1_path not in removed_paths:
4339 unnecessary_sha1_files.append(sha1_path)
4340
4341
4342 for f in affected_grds:
4343 file_path = f.LocalPath()
4344 old_id_to_msg_map = {}
4345 new_id_to_msg_map = {}
4346 if file_path.endswith('.grdp'):
4347 if f.OldContents():
4348 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394349 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144350 if f.NewContents():
4351 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394352 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144353 else:
4354 if f.OldContents():
4355 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394356 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144357 if f.NewContents():
4358 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394359 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144360
4361 # Compute added, removed and modified message IDs.
4362 old_ids = set(old_id_to_msg_map)
4363 new_ids = set(new_id_to_msg_map)
4364 added_ids = new_ids - old_ids
4365 removed_ids = old_ids - new_ids
4366 modified_ids = set([])
4367 for key in old_ids.intersection(new_ids):
4368 if (old_id_to_msg_map[key].FormatXml()
4369 != new_id_to_msg_map[key].FormatXml()):
4370 modified_ids.add(key)
4371
4372 grd_name, ext = input_api.os_path.splitext(
4373 input_api.os_path.basename(file_path))
4374 screenshots_dir = input_api.os_path.join(
4375 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4376
4377 # Check the screenshot directory for .png files. Warn if there is any.
4378 for png_path in affected_png_paths:
4379 if png_path.startswith(screenshots_dir):
4380 unnecessary_screenshots.append(png_path)
4381
4382 for added_id in added_ids:
4383 _CheckScreenshotAdded(screenshots_dir, added_id)
4384
4385 for modified_id in modified_ids:
4386 _CheckScreenshotAdded(screenshots_dir, modified_id)
4387
4388 for removed_id in removed_ids:
4389 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4390
4391 results = []
4392 if unnecessary_screenshots:
4393 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394394 'Do not include actual screenshots in the changelist. Run '
4395 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144396 sorted(unnecessary_screenshots)))
4397
4398 if missing_sha1:
4399 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394400 'You are adding or modifying UI strings.\n'
4401 'To ensure the best translations, take screenshots of the relevant UI '
4402 '(https://g.co/chrome/translation) and add these files to your '
4403 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144404
4405 if unnecessary_sha1_files:
4406 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394407 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144408 sorted(unnecessary_sha1_files)))
4409
4410 return results