blob: 42dcbe7f4f174db83a361e9afa7788b64fb21248 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
28 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
29 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1430 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5432 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4034)
[email protected]ca8d1982009-02-19 16:33:1235
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Fragment of a regular expression that matches C++ and Objective-C++
38# implementation files.
39_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
40
wnwenbdc444e2016-05-25 13:44:1541
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1942# Fragment of a regular expression that matches C++ and Objective-C++
43# header files.
44_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
45
46
[email protected]06e6d0ff2012-12-11 01:36:4447# Regular expression that matches code only used for test binaries
48# (best effort).
49_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0450 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4452 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1253 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1854 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4455 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0456 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0557 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0458 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4759 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0460 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0861 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0462 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4463)
[email protected]ca8d1982009-02-19 16:33:1264
Daniel Bratell609102be2019-03-27 20:53:2165_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1566
[email protected]eea609a2011-11-18 13:10:1267_TEST_ONLY_WARNING = (
68 'You might be calling functions intended only for testing from\n'
69 'production code. It is OK to ignore this warning if you know what\n'
70 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5871 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1272
73
[email protected]cf9b78f2012-11-14 11:40:2874_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4075 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2176 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
77 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2878
wnwenbdc444e2016-05-25 13:44:1579
Daniel Bratell609102be2019-03-27 20:53:2180# Format: Sequence of tuples containing:
81# * String pattern or, if starting with a slash, a regular expression.
82# * Sequence of strings to show when the pattern matches.
83# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4184_BANNED_JAVA_FUNCTIONS = (
85 (
86 'StrictMode.allowThreadDiskReads()',
87 (
88 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
89 'directly.',
90 ),
91 False,
92 ),
93 (
94 'StrictMode.allowThreadDiskWrites()',
95 (
96 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
97 'directly.',
98 ),
99 False,
100 ),
101)
102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59107_BANNED_OBJC_FUNCTIONS = (
108 (
109 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20110 (
111 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59112 'prohibited. Please use CrTrackingArea instead.',
113 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
114 ),
115 False,
116 ),
117 (
[email protected]eaae1972014-04-16 04:17:26118 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20119 (
120 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59121 'instead.',
122 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
123 ),
124 False,
125 ),
126 (
127 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20128 (
129 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59130 'Please use |convertPoint:(point) fromView:nil| instead.',
131 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
132 ),
133 True,
134 ),
135 (
136 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20137 (
138 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59139 'Please use |convertPoint:(point) toView:nil| instead.',
140 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 ),
142 True,
143 ),
144 (
145 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20146 (
147 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59148 'Please use |convertRect:(point) fromView:nil| instead.',
149 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
150 ),
151 True,
152 ),
153 (
154 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59157 'Please use |convertRect:(point) toView:nil| instead.',
158 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
159 ),
160 True,
161 ),
162 (
163 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20164 (
165 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59166 'Please use |convertSize:(point) fromView:nil| instead.',
167 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
168 ),
169 True,
170 ),
171 (
172 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20173 (
174 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59175 'Please use |convertSize:(point) toView:nil| instead.',
176 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
177 ),
178 True,
179 ),
jif65398702016-10-27 10:19:48180 (
181 r"/\s+UTF8String\s*]",
182 (
183 'The use of -[NSString UTF8String] is dangerous as it can return null',
184 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
185 'Please use |SysNSStringToUTF8| instead.',
186 ),
187 True,
188 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34189 (
190 r'__unsafe_unretained',
191 (
192 'The use of __unsafe_unretained is almost certainly wrong, unless',
193 'when interacting with NSFastEnumeration or NSInvocation.',
194 'Please use __weak in files build with ARC, nothing otherwise.',
195 ),
196 False,
197 ),
Avi Drissman7382afa02019-04-29 23:27:13198 (
199 'freeWhenDone:NO',
200 (
201 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
202 'Foundation types is prohibited.',
203 ),
204 True,
205 ),
[email protected]127f18ec2012-06-16 05:05:59206)
207
Daniel Bratell609102be2019-03-27 20:53:21208# Format: Sequence of tuples containing:
209# * String pattern or, if starting with a slash, a regular expression.
210# * Sequence of strings to show when the pattern matches.
211# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54212_BANNED_IOS_OBJC_FUNCTIONS = (
213 (
214 r'/\bTEST[(]',
215 (
216 'TEST() macro should not be used in Objective-C++ code as it does not ',
217 'drain the autorelease pool at the end of the test. Use TEST_F() ',
218 'macro instead with a fixture inheriting from PlatformTest (or a ',
219 'typedef).'
220 ),
221 True,
222 ),
223 (
224 r'/\btesting::Test\b',
225 (
226 'testing::Test should not be used in Objective-C++ code as it does ',
227 'not drain the autorelease pool at the end of the test. Use ',
228 'PlatformTest instead.'
229 ),
230 True,
231 ),
232)
233
Peter K. Lee6c03ccff2019-07-15 14:40:05234# Format: Sequence of tuples containing:
235# * String pattern or, if starting with a slash, a regular expression.
236# * Sequence of strings to show when the pattern matches.
237# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
238_BANNED_IOS_EGTEST_FUNCTIONS = (
239 (
240 r'/\bEXPECT_OCMOCK_VERIFY\b',
241 (
242 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
243 'it is meant for GTests. Use [mock verify] instead.'
244 ),
245 True,
246 ),
247)
248
danakj7a2b7082019-05-21 21:13:51249# Directories that contain deprecated Bind() or Callback types.
250# Find sub-directories from a given directory by running:
251# for i in `find . -maxdepth 1 -type d`; do
252# echo "-- $i"
253# (cd $i; git grep -P 'base::(Bind\(|(Callback<|Closure))'|wc -l)
254# done
255#
256# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
257# when they have been converted to modern callback types (OnceCallback,
258# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
259# checks for them and prevent regressions.
260_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
261 '^android_webview/browser/',
262 '^apps/',
263 '^ash/',
danakj7a2b7082019-05-21 21:13:51264 '^base/callback.h', # Intentional.
265 '^chrome/app/',
266 '^chrome/browser/',
267 '^chrome/chrome_elf/',
268 '^chrome/chrome_watcher/',
269 '^chrome/common/',
270 '^chrome/installer/',
271 '^chrome/notification_helper/',
272 '^chrome/renderer/',
273 '^chrome/services/',
274 '^chrome/test/',
275 '^chrome/tools/',
276 '^chrome/utility/',
277 '^chromecast/app/',
278 '^chromecast/browser/',
279 '^chromecast/crash/',
280 '^chromecast/media/',
281 '^chromecast/metrics/',
282 '^chromecast/net/',
283 '^chromeos/attestation/',
284 '^chromeos/audio/',
285 '^chromeos/components/',
286 '^chromeos/cryptohome/',
287 '^chromeos/dbus/',
288 '^chromeos/geolocation/',
289 '^chromeos/login/',
290 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51291 '^chromeos/process_proxy/',
292 '^chromeos/services/',
293 '^chromeos/settings/',
294 '^chromeos/timezone/',
295 '^chromeos/tpm/',
296 '^components/arc/',
297 '^components/assist_ranker/',
298 '^components/autofill/',
299 '^components/autofill_assistant/',
300 '^components/bookmarks/',
301 '^components/browser_sync/',
302 '^components/browser_watcher/',
303 '^components/browsing_data/',
304 '^components/cast_channel/',
305 '^components/certificate_transparency/',
306 '^components/chromeos_camera/',
307 '^components/component_updater/',
308 '^components/content_settings/',
309 '^components/crash/',
310 '^components/cronet/',
311 '^components/data_reduction_proxy/',
312 '^components/discardable_memory/',
313 '^components/dom_distiller/',
314 '^components/domain_reliability/',
315 '^components/download/',
316 '^components/drive/',
317 '^components/exo/',
318 '^components/favicon/',
319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
323 '^components/google/',
324 '^components/guest_view/',
325 '^components/heap_profiling/',
326 '^components/history/',
327 '^components/image_fetcher/',
328 '^components/invalidation/',
329 '^components/keyed_service/',
330 '^components/login/',
331 '^components/metrics/',
332 '^components/metrics_services_manager/',
333 '^components/nacl/',
334 '^components/navigation_interception/',
335 '^components/net_log/',
336 '^components/network_time/',
337 '^components/ntp_snippets/',
338 '^components/ntp_tiles/',
339 '^components/offline_items_collection/',
340 '^components/offline_pages/',
341 '^components/omnibox/',
342 '^components/ownership/',
343 '^components/pairing/',
344 '^components/password_manager/',
345 '^components/payments/',
346 '^components/plugins/',
347 '^components/policy/',
348 '^components/pref_registry/',
349 '^components/prefs/',
danakj7a2b7082019-05-21 21:13:51350 '^components/proxy_config/',
351 '^components/quirks/',
352 '^components/rappor/',
353 '^components/remote_cocoa/',
354 '^components/renderer_context_menu/',
355 '^components/rlz/',
356 '^components/safe_browsing/',
357 '^components/search_engines/',
358 '^components/search_provider_logos/',
359 '^components/security_interstitials/',
360 '^components/security_state/',
361 '^components/services/',
362 '^components/sessions/',
363 '^components/signin/',
364 '^components/ssl_errors/',
365 '^components/storage_monitor/',
366 '^components/subresource_filter/',
367 '^components/suggestions/',
368 '^components/supervised_user_error_page/',
369 '^components/sync/',
370 '^components/sync_bookmarks/',
371 '^components/sync_device_info/',
372 '^components/sync_preferences/',
373 '^components/sync_sessions/',
374 '^components/test/',
375 '^components/tracing/',
376 '^components/translate/',
377 '^components/ukm/',
378 '^components/update_client/',
379 '^components/upload_list/',
380 '^components/variations/',
381 '^components/visitedlink/',
382 '^components/web_cache/',
383 '^components/web_resource/',
danakj7a2b7082019-05-21 21:13:51384 '^components/webcrypto/',
385 '^components/webdata/',
386 '^components/webdata_services/',
387 '^components/wifi/',
388 '^components/zoom/',
389 '^content/app/',
390 '^content/browser/',
391 '^content/child/',
392 '^content/common/',
393 '^content/public/',
394 '^content/renderer/android/',
395 '^content/renderer/fetchers/',
396 '^content/renderer/image_downloader/',
397 '^content/renderer/input/',
398 '^content/renderer/java/',
399 '^content/renderer/media/',
400 '^content/renderer/media_capture_from_element/',
401 '^content/renderer/media_recorder/',
402 '^content/renderer/p2p/',
403 '^content/renderer/pepper/',
404 '^content/renderer/service_worker/',
405 '^content/renderer/worker/',
406 '^content/test/',
407 '^content/utility/',
408 '^dbus/',
409 '^device/base/',
410 '^device/bluetooth/',
411 '^device/fido/',
412 '^device/gamepad/',
413 '^device/udev_linux/',
414 '^device/vr/',
415 '^extensions/',
416 '^gin/',
417 '^google_apis/dive/',
418 '^google_apis/gaia/',
419 '^google_apis/gcm/',
420 '^headless/',
421 '^ios/chrome/',
422 '^ios/components/',
423 '^ios/net/',
424 '^ios/web/',
425 '^ios/web_view/',
426 '^ipc/',
427 '^media/audio/',
428 '^media/base/',
429 '^media/capture/',
430 '^media/cast/',
431 '^media/cdm/',
432 '^media/device_monitors/',
433 '^media/ffmpeg/',
434 '^media/filters/',
435 '^media/formats/',
436 '^media/gpu/',
437 '^media/mojo/',
438 '^media/muxers/',
439 '^media/remoting/',
440 '^media/renderers/',
441 '^media/test/',
442 '^mojo/core/',
443 '^mojo/public/',
444 '^net/',
445 '^ppapi/proxy/',
446 '^ppapi/shared_impl/',
447 '^ppapi/tests/',
448 '^ppapi/thunk/',
449 '^remoting/base/',
450 '^remoting/client/',
451 '^remoting/codec/',
452 '^remoting/host/',
453 '^remoting/internal/',
454 '^remoting/ios/',
455 '^remoting/protocol/',
456 '^remoting/signaling/',
457 '^remoting/test/',
458 '^sandbox/linux/',
459 '^sandbox/win/',
460 '^services/',
461 '^storage/browser/',
462 '^testing/gmock_mutant.h',
463 '^testing/libfuzzer/',
464 '^third_party/blink/',
465 '^third_party/crashpad/crashpad/test/gtest_main.cc',
466 '^third_party/leveldatabase/leveldb_chrome.cc',
467 '^third_party/boringssl/gtest_main_chromium.cc',
468 '^third_party/cacheinvalidation/overrides/' +
469 'google/cacheinvalidation/deps/callback.h',
470 '^third_party/libaddressinput/chromium/chrome_address_validator.cc',
471 '^third_party/zlib/google/',
472 '^tools/android/',
473 '^tools/clang/base_bind_rewriters/', # Intentional.
474 '^tools/gdb/gdb_chrome.py', # Intentional.
475 '^ui/accelerated_widget_mac/',
476 '^ui/android/',
477 '^ui/aura/',
478 '^ui/base/',
479 '^ui/compositor/',
480 '^ui/display/',
481 '^ui/events/',
482 '^ui/gfx/',
483 '^ui/message_center/',
danakj7a2b7082019-05-21 21:13:51484 '^ui/snapshot/',
485 '^ui/views_content_client/',
486 '^ui/wm/',
487))
[email protected]127f18ec2012-06-16 05:05:59488
Daniel Bratell609102be2019-03-27 20:53:21489# Format: Sequence of tuples containing:
490# * String pattern or, if starting with a slash, a regular expression.
491# * Sequence of strings to show when the pattern matches.
492# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
493# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59494_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20495 (
Dave Tapuska98199b612019-07-10 13:30:44496 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53497 (
498 'New code should not use NULL. Use nullptr instead.',
499 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20500 False,
thomasandersone7caaa9b2017-03-29 19:22:53501 (),
502 ),
Antonio Gomes07300d02019-03-13 20:59:57503 # Make sure that gtest's FRIEND_TEST() macro is not used; the
504 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
505 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53506 (
[email protected]23e6cbc2012-06-16 18:51:20507 'FRIEND_TEST(',
508 (
[email protected]e3c945502012-06-26 20:01:49509 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20510 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
511 ),
512 False,
[email protected]7345da02012-11-27 14:31:49513 (),
[email protected]23e6cbc2012-06-16 18:51:20514 ),
515 (
Dave Tapuska98199b612019-07-10 13:30:44516 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53517 (
518 'Chrome clients wishing to select events on X windows should use',
519 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
520 'you are selecting events from the GPU process, or if you are using',
521 'an XDisplay other than gfx::GetXDisplay().',
522 ),
523 True,
524 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40525 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04526 r"^ui[\\/]gl[\\/].*\.cc$",
527 r"^media[\\/]gpu[\\/].*\.cc$",
528 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53529 ),
530 ),
531 (
Dave Tapuska98199b612019-07-10 13:30:44532 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20533 (
thomasanderson11aa41d2017-06-08 22:22:38534 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20535 ),
536 True,
537 (
Egor Paskoce145c42018-09-28 19:31:04538 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
539 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
540 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20541 ),
542 ),
543 (
tomhudsone2c14d552016-05-26 17:07:46544 'setMatrixClip',
545 (
546 'Overriding setMatrixClip() is prohibited; ',
547 'the base function is deprecated. ',
548 ),
549 True,
550 (),
551 ),
552 (
[email protected]52657f62013-05-20 05:30:31553 'SkRefPtr',
554 (
555 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22556 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31557 ),
558 True,
559 (),
560 ),
561 (
562 'SkAutoRef',
563 (
564 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22565 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31566 ),
567 True,
568 (),
569 ),
570 (
571 'SkAutoTUnref',
572 (
573 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22574 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31575 ),
576 True,
577 (),
578 ),
579 (
580 'SkAutoUnref',
581 (
582 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
583 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22584 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31585 ),
586 True,
587 (),
588 ),
[email protected]d89eec82013-12-03 14:10:59589 (
590 r'/HANDLE_EINTR\(.*close',
591 (
592 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
593 'descriptor will be closed, and it is incorrect to retry the close.',
594 'Either call close directly and ignore its return value, or wrap close',
595 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
596 ),
597 True,
598 (),
599 ),
600 (
601 r'/IGNORE_EINTR\((?!.*close)',
602 (
603 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
604 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
605 ),
606 True,
607 (
608 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04609 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
610 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59611 ),
612 ),
[email protected]ec5b3f02014-04-04 18:43:43613 (
614 r'/v8::Extension\(',
615 (
616 'Do not introduce new v8::Extensions into the code base, use',
617 'gin::Wrappable instead. See http://crbug.com/334679',
618 ),
619 True,
[email protected]f55c90ee62014-04-12 00:50:03620 (
Egor Paskoce145c42018-09-28 19:31:04621 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03622 ),
[email protected]ec5b3f02014-04-04 18:43:43623 ),
skyostilf9469f72015-04-20 10:38:52624 (
jame2d1a952016-04-02 00:27:10625 '#pragma comment(lib,',
626 (
627 'Specify libraries to link with in build files and not in the source.',
628 ),
629 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41630 (
tzik3f295992018-12-04 20:32:23631 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04632 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41633 ),
jame2d1a952016-04-02 00:27:10634 ),
fdorayc4ac18d2017-05-01 21:39:59635 (
Gabriel Charette7cc6c432018-04-25 20:52:02636 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59637 (
638 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
639 ),
640 False,
641 (),
642 ),
643 (
Gabriel Charette7cc6c432018-04-25 20:52:02644 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59645 (
646 'Consider using THREAD_CHECKER macros instead of the class directly.',
647 ),
648 False,
649 (),
650 ),
dbeamb6f4fde2017-06-15 04:03:06651 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06652 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
653 (
654 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
655 'deprecated (http://crbug.com/634507). Please avoid converting away',
656 'from the Time types in Chromium code, especially if any math is',
657 'being done on time values. For interfacing with platform/library',
658 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
659 'type converter methods instead. For faking TimeXXX values (for unit',
660 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
661 'other use cases, please contact base/time/OWNERS.',
662 ),
663 False,
664 (),
665 ),
666 (
dbeamb6f4fde2017-06-15 04:03:06667 'CallJavascriptFunctionUnsafe',
668 (
669 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
670 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
671 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
672 ),
673 False,
674 (
Egor Paskoce145c42018-09-28 19:31:04675 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
676 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
677 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06678 ),
679 ),
dskiba1474c2bfd62017-07-20 02:19:24680 (
681 'leveldb::DB::Open',
682 (
683 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
684 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
685 "Chrome's tracing, making their memory usage visible.",
686 ),
687 True,
688 (
689 r'^third_party/leveldatabase/.*\.(cc|h)$',
690 ),
Gabriel Charette0592c3a2017-07-26 12:02:04691 ),
692 (
Chris Mumfordc38afb62017-10-09 17:55:08693 'leveldb::NewMemEnv',
694 (
695 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58696 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
697 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08698 ),
699 True,
700 (
701 r'^third_party/leveldatabase/.*\.(cc|h)$',
702 ),
703 ),
704 (
Gabriel Charetted9839bc2017-07-29 14:17:47705 'RunLoop::QuitCurrent',
706 (
Robert Liao64b7ab22017-08-04 23:03:43707 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
708 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47709 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41710 False,
Gabriel Charetted9839bc2017-07-29 14:17:47711 (),
Gabriel Charettea44975052017-08-21 23:14:04712 ),
713 (
714 'base::ScopedMockTimeMessageLoopTaskRunner',
715 (
Gabriel Charette87cc1af2018-04-25 20:52:51716 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11717 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51718 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
719 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
720 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04721 ),
Gabriel Charette87cc1af2018-04-25 20:52:51722 False,
Gabriel Charettea44975052017-08-21 23:14:04723 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57724 ),
725 (
Dave Tapuska98199b612019-07-10 13:30:44726 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57727 (
728 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02729 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57730 ),
731 True,
732 (),
Francois Doray43670e32017-09-27 12:40:38733 ),
734 (
Peter Kasting991618a62019-06-17 22:00:09735 r'/\bstd::stoi\b',
736 (
737 'std::stoi uses exceptions to communicate results. ',
738 'Use base::StringToInt() instead.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
742 ),
743 (
744 r'/\bstd::stol\b',
745 (
746 'std::stol uses exceptions to communicate results. ',
747 'Use base::StringToInt() instead.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
751 ),
752 (
753 r'/\bstd::stoul\b',
754 (
755 'std::stoul uses exceptions to communicate results. ',
756 'Use base::StringToUint() instead.',
757 ),
758 True,
759 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
760 ),
761 (
762 r'/\bstd::stoll\b',
763 (
764 'std::stoll uses exceptions to communicate results. ',
765 'Use base::StringToInt64() instead.',
766 ),
767 True,
768 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
769 ),
770 (
771 r'/\bstd::stoull\b',
772 (
773 'std::stoull uses exceptions to communicate results. ',
774 'Use base::StringToUint64() instead.',
775 ),
776 True,
777 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
778 ),
779 (
780 r'/\bstd::stof\b',
781 (
782 'std::stof uses exceptions to communicate results. ',
783 'For locale-independent values, e.g. reading numbers from disk',
784 'profiles, use base::StringToDouble().',
785 'For user-visible values, parse using ICU.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
789 ),
790 (
791 r'/\bstd::stod\b',
792 (
793 'std::stod uses exceptions to communicate results. ',
794 'For locale-independent values, e.g. reading numbers from disk',
795 'profiles, use base::StringToDouble().',
796 'For user-visible values, parse using ICU.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
800 ),
801 (
802 r'/\bstd::stold\b',
803 (
804 'std::stold uses exceptions to communicate results. ',
805 'For locale-independent values, e.g. reading numbers from disk',
806 'profiles, use base::StringToDouble().',
807 'For user-visible values, parse using ICU.',
808 ),
809 True,
810 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
811 ),
812 (
Daniel Bratell69334cc2019-03-26 11:07:45813 r'/\bstd::to_string\b',
814 (
815 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09816 'For locale-independent strings, e.g. writing numbers to disk',
817 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45818 'For user-visible strings, use base::FormatNumber() and',
819 'the related functions in base/i18n/number_formatting.h.',
820 ),
Peter Kasting991618a62019-06-17 22:00:09821 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21822 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45823 ),
824 (
825 r'/\bstd::shared_ptr\b',
826 (
827 'std::shared_ptr should not be used. Use scoped_refptr instead.',
828 ),
829 True,
Daniel Bratell609102be2019-03-27 20:53:21830 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
831 ),
832 (
Peter Kasting991618a62019-06-17 22:00:09833 r'/\bstd::weak_ptr\b',
834 (
835 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
836 ),
837 True,
838 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
839 ),
840 (
Daniel Bratell609102be2019-03-27 20:53:21841 r'/\blong long\b',
842 (
843 'long long is banned. Use stdint.h if you need a 64 bit number.',
844 ),
845 False, # Only a warning since it is already used.
846 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
847 ),
848 (
849 r'/\bstd::bind\b',
850 (
851 'std::bind is banned because of lifetime risks.',
852 'Use base::BindOnce or base::BindRepeating instead.',
853 ),
854 True,
855 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
856 ),
857 (
858 r'/\b#include <chrono>\b',
859 (
860 '<chrono> overlaps with Time APIs in base. Keep using',
861 'base classes.',
862 ),
863 True,
864 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
865 ),
866 (
867 r'/\b#include <exception>\b',
868 (
869 'Exceptions are banned and disabled in Chromium.',
870 ),
871 True,
872 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
873 ),
874 (
875 r'/\bstd::function\b',
876 (
877 'std::function is banned. Instead use base::Callback which directly',
878 'supports Chromium\'s weak pointers, ref counting and more.',
879 ),
Peter Kasting991618a62019-06-17 22:00:09880 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21881 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
882 ),
883 (
884 r'/\b#include <random>\b',
885 (
886 'Do not use any random number engines from <random>. Instead',
887 'use base::RandomBitGenerator.',
888 ),
889 True,
890 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
891 ),
892 (
893 r'/\bstd::ratio\b',
894 (
895 'std::ratio is banned by the Google Style Guide.',
896 ),
897 True,
898 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45899 ),
900 (
Francois Doray43670e32017-09-27 12:40:38901 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
902 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
903 (
904 'Use the new API in base/threading/thread_restrictions.h.',
905 ),
Gabriel Charette04b138f2018-08-06 00:03:22906 False,
Francois Doray43670e32017-09-27 12:40:38907 (),
908 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38909 (
danakj7a2b7082019-05-21 21:13:51910 r'/\bbase::Bind\(',
911 (
912 'Please use base::Bind{Once,Repeating} instead',
913 'of base::Bind. (crbug.com/714018)',
914 ),
915 False,
916 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
917 ),
918 (
919 r'/\bbase::Callback[<:]',
920 (
921 'Please use base::{Once,Repeating}Callback instead',
922 'of base::Callback. (crbug.com/714018)',
923 ),
924 False,
925 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
926 ),
927 (
928 r'/\bbase::Closure\b',
929 (
930 'Please use base::{Once,Repeating}Closure instead',
931 'of base::Closure. (crbug.com/714018)',
932 ),
933 False,
934 _NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,
935 ),
936 (
Alex Ilin5929abe32019-04-03 17:09:34937 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45938 (
939 'base::SharedMemory is deprecated. Please use',
940 '{Writable,ReadOnly}SharedMemoryRegion instead.',
941 ),
942 False,
943 (),
944 ),
945 (
Michael Giuffrida7f93d6922019-04-19 14:39:58946 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19947 (
948 'RunMessageLoop is deprecated, use RunLoop instead.',
949 ),
950 False,
951 (),
952 ),
953 (
Dave Tapuska98199b612019-07-10 13:30:44954 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19955 (
956 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
957 ),
958 False,
959 (),
960 ),
961 (
Dave Tapuska98199b612019-07-10 13:30:44962 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19963 (
964 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
965 "if you're convinced you need this.",
966 ),
967 False,
968 (),
969 ),
970 (
Dave Tapuska98199b612019-07-10 13:30:44971 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19972 (
973 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04974 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19975 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
976 'async events instead of flushing threads.',
977 ),
978 False,
979 (),
980 ),
981 (
982 r'MessageLoopRunner',
983 (
984 'MessageLoopRunner is deprecated, use RunLoop instead.',
985 ),
986 False,
987 (),
988 ),
989 (
Dave Tapuska98199b612019-07-10 13:30:44990 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19991 (
992 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
993 "gab@ if you found a use case where this is the only solution.",
994 ),
995 False,
996 (),
997 ),
998 (
Victor Costane48a2e82019-03-15 22:02:34999 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:161000 (
Victor Costane48a2e82019-03-15 22:02:341001 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:161002 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
1003 ),
1004 True,
1005 (
1006 r'^sql/initialization\.(cc|h)$',
1007 r'^third_party/sqlite/.*\.(c|cc|h)$',
1008 ),
1009 ),
Matt Menke7f520a82018-03-28 21:38:371010 (
1011 'net::URLFetcher',
1012 (
1013 'net::URLFetcher should no longer be used in content embedders. ',
1014 'Instead, use network::SimpleURLLoader instead, which supports ',
1015 'an out-of-process network stack. ',
1016 'net::URLFetcher may still be used in binaries that do not embed',
1017 'content.',
1018 ),
Matt Menke59716d02018-04-05 12:45:531019 False,
Matt Menke7f520a82018-03-28 21:38:371020 (
Egor Paskoce145c42018-09-28 19:31:041021 r'^ios[\\/].*\.(cc|h)$',
1022 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:371023 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:041024 r'^net[\\/].*\.(cc|h)$',
1025 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Fabrice de Gans-Riberi9345311c2019-08-30 23:33:431026 r'^fuchsia/base/test_devtools_list_fetcher\.cc$',
Matt Menke7f520a82018-03-28 21:38:371027 ),
1028 ),
jdoerried7d10ab2018-04-27 10:46:131029 (
Dave Tapuska98199b612019-07-10 13:30:441030 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:471031 (
1032 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
1033 'base::RandomShuffle instead.'
1034 ),
1035 True,
1036 (),
1037 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:241038 (
1039 'ios/web/public/test/http_server',
1040 (
1041 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
1042 ),
1043 False,
1044 (),
1045 ),
Robert Liao764c9492019-01-24 18:46:281046 (
1047 'GetAddressOf',
1048 (
1049 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
1050 'implicated in a few leaks. Use operator& instead.'
1051 ),
1052 True,
1053 (),
1054 ),
Antonio Gomes07300d02019-03-13 20:59:571055 (
1056 'DEFINE_TYPE_CASTS',
1057 (
1058 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
1059 '//third_party/blink/renderer/platform/casting.h.'
1060 ),
1061 True,
1062 (
1063 r'^third_party/blink/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Carlos Knippschildab192b8c2019-04-08 20:02:381066 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371067 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381068 (
1069 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1070 ),
1071 True,
1072 (),
1073 ),
Ben Lewisa9514602019-04-29 17:53:051074 (
1075 'SHFileOperation',
1076 (
1077 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1078 'complex functions to achieve the same goals. Use IFileOperation for ',
1079 'any esoteric actions instead.'
1080 ),
1081 True,
1082 (),
1083 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181084 (
Cliff Smolinsky81951642019-04-30 21:39:511085 'StringFromGUID2',
1086 (
1087 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1088 'Use base::win::String16FromGUID instead.'
1089 ),
1090 True,
1091 (
1092 r'/base/win/win_util_unittest.cc'
1093 ),
1094 ),
1095 (
1096 'StringFromCLSID',
1097 (
1098 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1099 'Use base::win::String16FromGUID instead.'
1100 ),
1101 True,
1102 (
1103 r'/base/win/win_util_unittest.cc'
1104 ),
1105 ),
1106 (
Avi Drissman7382afa02019-04-29 23:27:131107 'kCFAllocatorNull',
1108 (
1109 'The use of kCFAllocatorNull with the NoCopy creation of ',
1110 'CoreFoundation types is prohibited.',
1111 ),
1112 True,
1113 (),
1114 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291115 (
1116 'mojo::ConvertTo',
1117 (
1118 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1119 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1120 'StringTraits if you would like to convert between custom types and',
1121 'the wire format of mojom types.'
1122 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221123 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291124 (
Wezf89dec092019-09-11 19:38:331125 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1126 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291127 r'^third_party/blink/.*\.(cc|h)$',
1128 r'^content/renderer/.*\.(cc|h)$',
1129 ),
1130 ),
[email protected]127f18ec2012-06-16 05:05:591131)
1132
wnwenbdc444e2016-05-25 13:44:151133
mlamouria82272622014-09-16 18:45:041134_IPC_ENUM_TRAITS_DEPRECATED = (
1135 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501136 'See http://www.chromium.org/Home/chromium-security/education/'
1137 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041138
Stephen Martinis97a394142018-06-07 23:06:051139_LONG_PATH_ERROR = (
1140 'Some files included in this CL have file names that are too long (> 200'
1141 ' characters). If committed, these files will cause issues on Windows. See'
1142 ' https://crbug.com/612667 for more details.'
1143)
1144
Shenghua Zhangbfaa38b82017-11-16 21:58:021145_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041146 r".*[\\/]BuildHooksAndroidImpl\.java",
1147 r".*[\\/]LicenseContentProvider\.java",
1148 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281149 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021150]
[email protected]127f18ec2012-06-16 05:05:591151
Sean Kau46e29bc2017-08-28 16:31:161152# These paths contain test data and other known invalid JSON files.
1153_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041154 r'test[\\/]data[\\/]',
1155 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1156 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041157 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431158 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161159]
1160
1161
[email protected]b00342e7f2013-03-26 16:21:541162_VALID_OS_MACROS = (
1163 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081164 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541165 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121166 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541167 'OS_BSD',
1168 'OS_CAT', # For testing.
1169 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041170 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541171 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371172 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541173 'OS_IOS',
1174 'OS_LINUX',
1175 'OS_MACOSX',
1176 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211177 'OS_NACL_NONSFI',
1178 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121179 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541180 'OS_OPENBSD',
1181 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371182 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541183 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541184 'OS_WIN',
1185)
1186
1187
agrievef32bcc72016-04-04 14:57:401188_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391189 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361190 'base/android/jni_generator/jni_generator.pydeps',
1191 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221192 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361193 'build/android/gyp/aar.pydeps',
1194 'build/android/gyp/aidl.pydeps',
1195 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381196 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361197 'build/android/gyp/bytecode_processor.pydeps',
1198 'build/android/gyp/compile_resources.pydeps',
Tibor Goldschwendt84ec04c2019-08-23 21:19:091199 'build/android/gyp/create_app_bundle_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361200 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1201 'build/android/gyp/copy_ex.pydeps',
1202 'build/android/gyp/create_app_bundle.pydeps',
1203 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361204 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221205 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361206 'build/android/gyp/create_tool_wrapper.pydeps',
1207 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591208 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361209 'build/android/gyp/dex.pydeps',
1210 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361211 'build/android/gyp/filter_zip.pydeps',
1212 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361213 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361214 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581215 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361216 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261217 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361218 'build/android/gyp/javac.pydeps',
1219 'build/android/gyp/jinja_template.pydeps',
1220 'build/android/gyp/lint.pydeps',
1221 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361222 'build/android/gyp/merge_manifest.pydeps',
1223 'build/android/gyp/prepare_resources.pydeps',
1224 'build/android/gyp/proguard.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241225 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361226 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461227 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561228 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361229 'build/android/incremental_install/generate_android_manifest.pydeps',
1230 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221231 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401232 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041233 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361234 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411235 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:191236 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021237 'third_party/android_platform/development/scripts/stack.pydeps',
John Budorick207963292019-09-13 16:53:321238 'tools/android/avd/avd.pydeps',
agrievef32bcc72016-04-04 14:57:401239]
1240
wnwenbdc444e2016-05-25 13:44:151241
agrievef32bcc72016-04-04 14:57:401242_GENERIC_PYDEPS_FILES = [
anthonyvd7323c982019-09-11 14:36:421243 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131244 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421245 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1246 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131247 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061248 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221249 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401250]
1251
wnwenbdc444e2016-05-25 13:44:151252
agrievef32bcc72016-04-04 14:57:401253_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1254
1255
Eric Boren6fd2b932018-01-25 15:05:081256# Bypass the AUTHORS check for these accounts.
1257_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:291258 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
1259 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:081260 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:321261 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:591262 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451263 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591264 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:221265 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041266 ) | set('%[email protected]' % s
1267 for s in ('chromium-autoroll',)
1268 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301269 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081270
1271
Daniel Bratell65b033262019-04-23 08:17:061272def _IsCPlusPlusFile(input_api, file_path):
1273 """Returns True if this file contains C++-like code (and not Python,
1274 Go, Java, MarkDown, ...)"""
1275
1276 ext = input_api.os_path.splitext(file_path)[1]
1277 # This list is compatible with CppChecker.IsCppFile but we should
1278 # consider adding ".c" to it. If we do that we can use this function
1279 # at more places in the code.
1280 return ext in (
1281 '.h',
1282 '.cc',
1283 '.cpp',
1284 '.m',
1285 '.mm',
1286 )
1287
1288def _IsCPlusPlusHeaderFile(input_api, file_path):
1289 return input_api.os_path.splitext(file_path)[1] == ".h"
1290
1291
1292def _IsJavaFile(input_api, file_path):
1293 return input_api.os_path.splitext(file_path)[1] == ".java"
1294
1295
1296def _IsProtoFile(input_api, file_path):
1297 return input_api.os_path.splitext(file_path)[1] == ".proto"
1298
[email protected]55459852011-08-10 15:17:191299def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1300 """Attempts to prevent use of functions intended only for testing in
1301 non-testing code. For now this is just a best-effort implementation
1302 that ignores header files and may have some false positives. A
1303 better implementation would probably need a proper C++ parser.
1304 """
1305 # We only scan .cc files and the like, as the declaration of
1306 # for-testing functions in header files are hard to distinguish from
1307 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491308 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191309
jochenc0d4808c2015-07-27 09:25:421310 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191311 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091312 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191313 exclusion_pattern = input_api.re.compile(
1314 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1315 base_function_pattern, base_function_pattern))
1316
1317 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441318 black_list = (_EXCLUDED_PATHS +
1319 _TEST_CODE_EXCLUDED_PATHS +
1320 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191321 return input_api.FilterSourceFile(
1322 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491323 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191324 black_list=black_list)
1325
1326 problems = []
1327 for f in input_api.AffectedSourceFiles(FilterFile):
1328 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241329 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031330 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461331 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031332 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191333 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031334 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191335
1336 if problems:
[email protected]f7051d52013-04-02 18:31:421337 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031338 else:
1339 return []
[email protected]55459852011-08-10 15:17:191340
1341
Vaclav Brozek7dbc28c2018-03-27 08:35:231342def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1343 """This is a simplified version of
1344 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1345 """
1346 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1347 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1348 name_pattern = r'ForTest(s|ing)?'
1349 # Describes an occurrence of "ForTest*" inside a // comment.
1350 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1351 # Catch calls.
1352 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1353 # Ignore definitions. (Comments are ignored separately.)
1354 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1355
1356 problems = []
1357 sources = lambda x: input_api.FilterSourceFile(
1358 x,
1359 black_list=(('(?i).*test', r'.*\/junit\/')
1360 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491361 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231362 )
1363 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1364 local_path = f.LocalPath()
1365 is_inside_javadoc = False
1366 for line_number, line in f.ChangedContents():
1367 if is_inside_javadoc and javadoc_end_re.search(line):
1368 is_inside_javadoc = False
1369 if not is_inside_javadoc and javadoc_start_re.search(line):
1370 is_inside_javadoc = True
1371 if is_inside_javadoc:
1372 continue
1373 if (inclusion_re.search(line) and
1374 not comment_re.search(line) and
1375 not exclusion_re.search(line)):
1376 problems.append(
1377 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1378
1379 if problems:
1380 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1381 else:
1382 return []
1383
1384
[email protected]10689ca2011-09-02 02:31:541385def _CheckNoIOStreamInHeaders(input_api, output_api):
1386 """Checks to make sure no .h files include <iostream>."""
1387 files = []
1388 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1389 input_api.re.MULTILINE)
1390 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1391 if not f.LocalPath().endswith('.h'):
1392 continue
1393 contents = input_api.ReadFile(f)
1394 if pattern.search(contents):
1395 files.append(f)
1396
1397 if len(files):
yolandyandaabc6d2016-04-18 18:29:391398 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061399 'Do not #include <iostream> in header files, since it inserts static '
1400 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541401 '#include <ostream>. See http://crbug.com/94794',
1402 files) ]
1403 return []
1404
Danil Chapovalov3518f362018-08-11 16:13:431405def _CheckNoStrCatRedefines(input_api, output_api):
1406 """Checks no windows headers with StrCat redefined are included directly."""
1407 files = []
1408 pattern_deny = input_api.re.compile(
1409 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1410 input_api.re.MULTILINE)
1411 pattern_allow = input_api.re.compile(
1412 r'^#include\s"base/win/windows_defines.inc"',
1413 input_api.re.MULTILINE)
1414 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1415 contents = input_api.ReadFile(f)
1416 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1417 files.append(f.LocalPath())
1418
1419 if len(files):
1420 return [output_api.PresubmitError(
1421 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1422 'directly since they pollute code with StrCat macro. Instead, '
1423 'include matching header from base/win. See http://crbug.com/856536',
1424 files) ]
1425 return []
1426
[email protected]10689ca2011-09-02 02:31:541427
[email protected]72df4e782012-06-21 16:28:181428def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521429 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181430 problems = []
1431 for f in input_api.AffectedFiles():
1432 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1433 continue
1434
1435 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041436 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181437 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1438
1439 if not problems:
1440 return []
1441 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1442 '\n'.join(problems))]
1443
Dominic Battre033531052018-09-24 15:45:341444def _CheckNoDISABLETypoInTests(input_api, output_api):
1445 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1446
1447 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1448 instead of DISABLED_. To filter false positives, reports are only generated
1449 if a corresponding MAYBE_ line exists.
1450 """
1451 problems = []
1452
1453 # The following two patterns are looked for in tandem - is a test labeled
1454 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1455 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1456 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1457
1458 # This is for the case that a test is disabled on all platforms.
1459 full_disable_pattern = input_api.re.compile(
1460 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1461 input_api.re.MULTILINE)
1462
Katie Df13948e2018-09-25 07:33:441463 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341464 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1465 continue
1466
1467 # Search for MABYE_, DISABLE_ pairs.
1468 disable_lines = {} # Maps of test name to line number.
1469 maybe_lines = {}
1470 for line_num, line in f.ChangedContents():
1471 disable_match = disable_pattern.search(line)
1472 if disable_match:
1473 disable_lines[disable_match.group(1)] = line_num
1474 maybe_match = maybe_pattern.search(line)
1475 if maybe_match:
1476 maybe_lines[maybe_match.group(1)] = line_num
1477
1478 # Search for DISABLE_ occurrences within a TEST() macro.
1479 disable_tests = set(disable_lines.keys())
1480 maybe_tests = set(maybe_lines.keys())
1481 for test in disable_tests.intersection(maybe_tests):
1482 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1483
1484 contents = input_api.ReadFile(f)
1485 full_disable_match = full_disable_pattern.search(contents)
1486 if full_disable_match:
1487 problems.append(' %s' % f.LocalPath())
1488
1489 if not problems:
1490 return []
1491 return [
1492 output_api.PresubmitPromptWarning(
1493 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1494 '\n'.join(problems))
1495 ]
1496
[email protected]72df4e782012-06-21 16:28:181497
danakj61c1aa22015-10-26 19:55:521498def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571499 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521500 errors = []
1501 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1502 input_api.re.MULTILINE)
1503 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1504 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1505 continue
1506 for lnum, line in f.ChangedContents():
1507 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171508 errors.append(output_api.PresubmitError(
1509 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571510 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171511 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521512 return errors
1513
1514
Makoto Shimazu3ad422cd2019-05-08 02:35:141515def _FindHistogramNameInChunk(histogram_name, chunk):
1516 """Tries to find a histogram name or prefix in a line.
1517
1518 Returns the existence of the histogram name, or None if it needs more chunk
1519 to determine."""
mcasasb7440c282015-02-04 14:52:191520 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1521 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141522 if '<affected-histogram' in chunk:
1523 # If the tag is not completed, needs more chunk to get the name.
1524 if not '>' in chunk:
1525 return None
1526 if not 'name="' in chunk:
1527 return False
1528 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1529 # expect the only attribute is the name.
1530 histogram_prefix = chunk.split('"')[1]
1531 return histogram_prefix in histogram_name
1532 # Typically the whole histogram name should in the line.
1533 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191534
1535
1536def _CheckUmaHistogramChanges(input_api, output_api):
1537 """Check that UMA histogram names in touched lines can still be found in other
1538 lines of the patch or in histograms.xml. Note that this check would not catch
1539 the reverse: changes in histograms.xml not matched in the code itself."""
1540 touched_histograms = []
1541 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471542 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1543 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1544 name_pattern = r'"(.*?)"'
1545 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1546 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1547 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1548 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1549 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171550 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191551 for f in input_api.AffectedFiles():
1552 # If histograms.xml itself is modified, keep the modified lines for later.
1553 if f.LocalPath().endswith(('histograms.xml')):
1554 histograms_xml_modifications = f.ChangedContents()
1555 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471556 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1557 single_line_re = single_line_c_re
1558 split_line_prefix_re = split_line_c_prefix_re
1559 elif f.LocalPath().endswith(('java')):
1560 single_line_re = single_line_java_re
1561 split_line_prefix_re = split_line_java_prefix_re
1562 else:
mcasasb7440c282015-02-04 14:52:191563 continue
1564 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171565 if last_line_matched_prefix:
1566 suffix_found = split_line_suffix_re.search(line)
1567 if suffix_found :
1568 touched_histograms.append([suffix_found.group(1), f, line_num])
1569 last_line_matched_prefix = False
1570 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061571 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191572 if found:
1573 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171574 continue
1575 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191576
1577 # Search for the touched histogram names in the local modifications to
1578 # histograms.xml, and, if not found, on the base histograms.xml file.
1579 unmatched_histograms = []
1580 for histogram_info in touched_histograms:
1581 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141582 chunk = ''
mcasasb7440c282015-02-04 14:52:191583 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141584 chunk += line
1585 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1586 if histogram_name_found is None:
1587 continue
1588 chunk = ''
mcasasb7440c282015-02-04 14:52:191589 if histogram_name_found:
1590 break
1591 if not histogram_name_found:
1592 unmatched_histograms.append(histogram_info)
1593
eromanb90c82e7e32015-04-01 15:13:491594 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191595 problems = []
1596 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491597 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191598 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451599 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191600 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141601 chunk = ''
mcasasb7440c282015-02-04 14:52:191602 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141603 chunk += line
1604 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1605 chunk)
1606 if histogram_name_found is None:
1607 continue
1608 chunk = ''
mcasasb7440c282015-02-04 14:52:191609 if histogram_name_found:
1610 break
1611 if not histogram_name_found:
1612 problems.append(' [%s:%d] %s' %
1613 (f.LocalPath(), line_num, histogram_name))
1614
1615 if not problems:
1616 return []
1617 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1618 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491619 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191620
wnwenbdc444e2016-05-25 13:44:151621
yolandyandaabc6d2016-04-18 18:29:391622def _CheckFlakyTestUsage(input_api, output_api):
1623 """Check that FlakyTest annotation is our own instead of the android one"""
1624 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1625 files = []
1626 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1627 if f.LocalPath().endswith('Test.java'):
1628 if pattern.search(input_api.ReadFile(f)):
1629 files.append(f)
1630 if len(files):
1631 return [output_api.PresubmitError(
1632 'Use org.chromium.base.test.util.FlakyTest instead of '
1633 'android.test.FlakyTest',
1634 files)]
1635 return []
mcasasb7440c282015-02-04 14:52:191636
wnwenbdc444e2016-05-25 13:44:151637
[email protected]8ea5d4b2011-09-13 21:49:221638def _CheckNoNewWStrings(input_api, output_api):
1639 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271640 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221641 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201642 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571643 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341644 '/win/' in f.LocalPath() or
1645 'chrome_elf' in f.LocalPath() or
1646 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201647 continue
[email protected]8ea5d4b2011-09-13 21:49:221648
[email protected]a11dbe9b2012-08-07 01:32:581649 allowWString = False
[email protected]b5c24292011-11-28 14:38:201650 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581651 if 'presubmit: allow wstring' in line:
1652 allowWString = True
1653 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271654 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581655 allowWString = False
1656 else:
1657 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221658
[email protected]55463aa62011-10-12 00:48:271659 if not problems:
1660 return []
1661 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581662 ' If you are calling a cross-platform API that accepts a wstring, '
1663 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271664 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221665
1666
[email protected]2a8ac9c2011-10-19 17:20:441667def _CheckNoDEPSGIT(input_api, output_api):
1668 """Make sure .DEPS.git is never modified manually."""
1669 if any(f.LocalPath().endswith('.DEPS.git') for f in
1670 input_api.AffectedFiles()):
1671 return [output_api.PresubmitError(
1672 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1673 'automated system based on what\'s in DEPS and your changes will be\n'
1674 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501675 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1676 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441677 'for more information')]
1678 return []
1679
1680
tandriief664692014-09-23 14:51:471681def _CheckValidHostsInDEPS(input_api, output_api):
1682 """Checks that DEPS file deps are from allowed_hosts."""
1683 # Run only if DEPS file has been modified to annoy fewer bystanders.
1684 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1685 return []
1686 # Outsource work to gclient verify
1687 try:
John Budorickf20c0042019-04-25 23:23:401688 gclient_path = input_api.os_path.join(
1689 input_api.PresubmitLocalPath(),
1690 'third_party', 'depot_tools', 'gclient.py')
1691 input_api.subprocess.check_output(
1692 [input_api.python_executable, gclient_path, 'verify'],
1693 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471694 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201695 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471696 return [output_api.PresubmitError(
1697 'DEPS file must have only git dependencies.',
1698 long_text=error.output)]
1699
1700
[email protected]127f18ec2012-06-16 05:05:591701def _CheckNoBannedFunctions(input_api, output_api):
1702 """Make sure that banned functions are not used."""
1703 warnings = []
1704 errors = []
1705
wnwenbdc444e2016-05-25 13:44:151706 def IsBlacklisted(affected_file, blacklist):
1707 local_path = affected_file.LocalPath()
1708 for item in blacklist:
1709 if input_api.re.match(item, local_path):
1710 return True
1711 return False
1712
Peter K. Lee6c03ccff2019-07-15 14:40:051713 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541714 local_path = affected_file.LocalPath()
1715 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1716 return False
1717 basename = input_api.os_path.basename(local_path)
1718 if 'ios' in basename.split('_'):
1719 return True
1720 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1721 if sep and 'ios' in local_path.split(sep):
1722 return True
1723 return False
1724
wnwenbdc444e2016-05-25 13:44:151725 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1726 matched = False
1727 if func_name[0:1] == '/':
1728 regex = func_name[1:]
1729 if input_api.re.search(regex, line):
1730 matched = True
1731 elif func_name in line:
dchenge07de812016-06-20 19:27:171732 matched = True
wnwenbdc444e2016-05-25 13:44:151733 if matched:
dchenge07de812016-06-20 19:27:171734 problems = warnings
wnwenbdc444e2016-05-25 13:44:151735 if error:
dchenge07de812016-06-20 19:27:171736 problems = errors
wnwenbdc444e2016-05-25 13:44:151737 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1738 for message_line in message:
1739 problems.append(' %s' % message_line)
1740
Eric Stevensona9a980972017-09-23 00:04:411741 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1742 for f in input_api.AffectedFiles(file_filter=file_filter):
1743 for line_num, line in f.ChangedContents():
1744 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1745 CheckForMatch(f, line_num, line, func_name, message, error)
1746
[email protected]127f18ec2012-06-16 05:05:591747 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1748 for f in input_api.AffectedFiles(file_filter=file_filter):
1749 for line_num, line in f.ChangedContents():
1750 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151751 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591752
Peter K. Lee6c03ccff2019-07-15 14:40:051753 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541754 for line_num, line in f.ChangedContents():
1755 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1756 CheckForMatch(f, line_num, line, func_name, message, error)
1757
Peter K. Lee6c03ccff2019-07-15 14:40:051758 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1759 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1760 for line_num, line in f.ChangedContents():
1761 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1762 CheckForMatch(f, line_num, line, func_name, message, error)
1763
[email protected]127f18ec2012-06-16 05:05:591764 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1765 for f in input_api.AffectedFiles(file_filter=file_filter):
1766 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491767 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491768 if IsBlacklisted(f, excluded_paths):
1769 continue
wnwenbdc444e2016-05-25 13:44:151770 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591771
1772 result = []
1773 if (warnings):
1774 result.append(output_api.PresubmitPromptWarning(
1775 'Banned functions were used.\n' + '\n'.join(warnings)))
1776 if (errors):
1777 result.append(output_api.PresubmitError(
1778 'Banned functions were used.\n' + '\n'.join(errors)))
1779 return result
1780
1781
[email protected]6c063c62012-07-11 19:11:061782def _CheckNoPragmaOnce(input_api, output_api):
1783 """Make sure that banned functions are not used."""
1784 files = []
1785 pattern = input_api.re.compile(r'^#pragma\s+once',
1786 input_api.re.MULTILINE)
1787 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1788 if not f.LocalPath().endswith('.h'):
1789 continue
1790 contents = input_api.ReadFile(f)
1791 if pattern.search(contents):
1792 files.append(f)
1793
1794 if files:
1795 return [output_api.PresubmitError(
1796 'Do not use #pragma once in header files.\n'
1797 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1798 files)]
1799 return []
1800
[email protected]127f18ec2012-06-16 05:05:591801
[email protected]e7479052012-09-19 00:26:121802def _CheckNoTrinaryTrueFalse(input_api, output_api):
1803 """Checks to make sure we don't introduce use of foo ? true : false."""
1804 problems = []
1805 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1806 for f in input_api.AffectedFiles():
1807 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1808 continue
1809
1810 for line_num, line in f.ChangedContents():
1811 if pattern.match(line):
1812 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1813
1814 if not problems:
1815 return []
1816 return [output_api.PresubmitPromptWarning(
1817 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1818 '\n'.join(problems))]
1819
1820
[email protected]55f9f382012-07-31 11:02:181821def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281822 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181823 change. Breaking - rules is an error, breaking ! rules is a
1824 warning.
1825 """
mohan.reddyf21db962014-10-16 12:26:471826 import sys
[email protected]55f9f382012-07-31 11:02:181827 # We need to wait until we have an input_api object and use this
1828 # roundabout construct to import checkdeps because this file is
1829 # eval-ed and thus doesn't have __file__.
1830 original_sys_path = sys.path
1831 try:
1832 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471833 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181834 import checkdeps
[email protected]55f9f382012-07-31 11:02:181835 from rules import Rule
1836 finally:
1837 # Restore sys.path to what it was before.
1838 sys.path = original_sys_path
1839
1840 added_includes = []
rhalavati08acd232017-04-03 07:23:281841 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241842 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181843 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061844 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501845 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081846 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061847 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501848 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081849 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061850 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501851 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081852 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181853
[email protected]26385172013-05-09 23:11:351854 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181855
1856 error_descriptions = []
1857 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281858 error_subjects = set()
1859 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181860 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1861 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081862 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181863 description_with_path = '%s\n %s' % (path, rule_description)
1864 if rule_type == Rule.DISALLOW:
1865 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281866 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181867 else:
1868 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281869 warning_subjects.add("#includes")
1870
1871 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1872 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081873 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281874 description_with_path = '%s\n %s' % (path, rule_description)
1875 if rule_type == Rule.DISALLOW:
1876 error_descriptions.append(description_with_path)
1877 error_subjects.add("imports")
1878 else:
1879 warning_descriptions.append(description_with_path)
1880 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181881
Jinsuk Kim5a092672017-10-24 22:42:241882 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021883 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081884 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241885 description_with_path = '%s\n %s' % (path, rule_description)
1886 if rule_type == Rule.DISALLOW:
1887 error_descriptions.append(description_with_path)
1888 error_subjects.add("imports")
1889 else:
1890 warning_descriptions.append(description_with_path)
1891 warning_subjects.add("imports")
1892
[email protected]55f9f382012-07-31 11:02:181893 results = []
1894 if error_descriptions:
1895 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281896 'You added one or more %s that violate checkdeps rules.'
1897 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181898 error_descriptions))
1899 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421900 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281901 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181902 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281903 '%s? See relevant DEPS file(s) for details and contacts.' %
1904 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181905 warning_descriptions))
1906 return results
1907
1908
[email protected]fbcafe5a2012-08-08 15:31:221909def _CheckFilePermissions(input_api, output_api):
1910 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151911 if input_api.platform == 'win32':
1912 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291913 checkperms_tool = input_api.os_path.join(
1914 input_api.PresubmitLocalPath(),
1915 'tools', 'checkperms', 'checkperms.py')
1916 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471917 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391918 with input_api.CreateTemporaryFile() as file_list:
1919 for f in input_api.AffectedFiles():
1920 # checkperms.py file/directory arguments must be relative to the
1921 # repository.
1922 file_list.write(f.LocalPath() + '\n')
1923 file_list.close()
1924 args += ['--file-list', file_list.name]
1925 try:
1926 input_api.subprocess.check_output(args)
1927 return []
1928 except input_api.subprocess.CalledProcessError as error:
1929 return [output_api.PresubmitError(
1930 'checkperms.py failed:',
1931 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221932
1933
robertocn832f5992017-01-04 19:01:301934def _CheckTeamTags(input_api, output_api):
1935 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1936 checkteamtags_tool = input_api.os_path.join(
1937 input_api.PresubmitLocalPath(),
1938 'tools', 'checkteamtags', 'checkteamtags.py')
1939 args = [input_api.python_executable, checkteamtags_tool,
1940 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221941 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301942 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1943 'OWNERS']
1944 try:
1945 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:051946 warnings = input_api.subprocess.check_output(args + files).splitlines()
1947 if warnings:
1948 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:301949 return []
1950 except input_api.subprocess.CalledProcessError as error:
1951 return [output_api.PresubmitError(
1952 'checkteamtags.py failed:',
1953 long_text=error.output)]
1954
1955
[email protected]c8278b32012-10-30 20:35:491956def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1957 """Makes sure we don't include ui/aura/window_property.h
1958 in header files.
1959 """
1960 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1961 errors = []
1962 for f in input_api.AffectedFiles():
1963 if not f.LocalPath().endswith('.h'):
1964 continue
1965 for line_num, line in f.ChangedContents():
1966 if pattern.match(line):
1967 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1968
1969 results = []
1970 if errors:
1971 results.append(output_api.PresubmitError(
1972 'Header files should not include ui/aura/window_property.h', errors))
1973 return results
1974
1975
[email protected]70ca77752012-11-20 03:45:031976def _CheckForVersionControlConflictsInFile(input_api, f):
1977 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1978 errors = []
1979 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161980 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231981 # First-level headers in markdown look a lot like version control
1982 # conflict markers. http://daringfireball.net/projects/markdown/basics
1983 continue
[email protected]70ca77752012-11-20 03:45:031984 if pattern.match(line):
1985 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1986 return errors
1987
1988
1989def _CheckForVersionControlConflicts(input_api, output_api):
1990 """Usually this is not intentional and will cause a compile failure."""
1991 errors = []
1992 for f in input_api.AffectedFiles():
1993 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1994
1995 results = []
1996 if errors:
1997 results.append(output_api.PresubmitError(
1998 'Version control conflict markers found, please resolve.', errors))
1999 return results
2000
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202001
estadee17314a02017-01-12 16:22:162002def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2003 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2004 errors = []
2005 for f in input_api.AffectedFiles():
2006 for line_num, line in f.ChangedContents():
2007 if pattern.search(line):
2008 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2009
2010 results = []
2011 if errors:
2012 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502013 'Found Google support URL addressed by answer number. Please replace '
2014 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162015 return results
2016
[email protected]70ca77752012-11-20 03:45:032017
[email protected]06e6d0ff2012-12-11 01:36:442018def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2019 def FilterFile(affected_file):
2020 """Filter function for use with input_api.AffectedSourceFiles,
2021 below. This filters out everything except non-test files from
2022 top-level directories that generally speaking should not hard-code
2023 service URLs (e.g. src/android_webview/, src/content/ and others).
2024 """
2025 return input_api.FilterSourceFile(
2026 affected_file,
Egor Paskoce145c42018-09-28 19:31:042027 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442028 black_list=(_EXCLUDED_PATHS +
2029 _TEST_CODE_EXCLUDED_PATHS +
2030 input_api.DEFAULT_BLACK_LIST))
2031
reillyi38965732015-11-16 18:27:332032 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2033 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462034 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2035 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442036 problems = [] # items are (filename, line_number, line)
2037 for f in input_api.AffectedSourceFiles(FilterFile):
2038 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462039 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442040 problems.append((f.LocalPath(), line_num, line))
2041
2042 if problems:
[email protected]f7051d52013-04-02 18:31:422043 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442044 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582045 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442046 [' %s:%d: %s' % (
2047 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032048 else:
2049 return []
[email protected]06e6d0ff2012-12-11 01:36:442050
2051
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492052# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272053def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2054 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312055 The native_client_sdk directory is excluded because it has auto-generated PNG
2056 files for documentation.
[email protected]d2530012013-01-25 16:39:272057 """
[email protected]d2530012013-01-25 16:39:272058 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492059 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042060 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312061 file_filter = lambda f: input_api.FilterSourceFile(
2062 f, white_list=white_list, black_list=black_list)
2063 for f in input_api.AffectedFiles(include_deletes=False,
2064 file_filter=file_filter):
2065 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272066
2067 results = []
2068 if errors:
2069 results.append(output_api.PresubmitError(
2070 'The name of PNG files should not have abbreviations. \n'
2071 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2072 'Contact [email protected] if you have questions.', errors))
2073 return results
2074
2075
Daniel Cheng4dcdb6b2017-04-13 08:30:172076def _ExtractAddRulesFromParsedDeps(parsed_deps):
2077 """Extract the rules that add dependencies from a parsed DEPS file.
2078
2079 Args:
2080 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2081 add_rules = set()
2082 add_rules.update([
2083 rule[1:] for rule in parsed_deps.get('include_rules', [])
2084 if rule.startswith('+') or rule.startswith('!')
2085 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502086 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172087 {}).iteritems():
2088 add_rules.update([
2089 rule[1:] for rule in rules
2090 if rule.startswith('+') or rule.startswith('!')
2091 ])
2092 return add_rules
2093
2094
2095def _ParseDeps(contents):
2096 """Simple helper for parsing DEPS files."""
2097 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172098 class _VarImpl:
2099
2100 def __init__(self, local_scope):
2101 self._local_scope = local_scope
2102
2103 def Lookup(self, var_name):
2104 """Implements the Var syntax."""
2105 try:
2106 return self._local_scope['vars'][var_name]
2107 except KeyError:
2108 raise Exception('Var is not defined: %s' % var_name)
2109
2110 local_scope = {}
2111 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172112 'Var': _VarImpl(local_scope).Lookup,
2113 }
2114 exec contents in global_scope, local_scope
2115 return local_scope
2116
2117
2118def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082119 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412120 a set of DEPS entries that we should look up.
2121
2122 For a directory (rather than a specific filename) we fake a path to
2123 a specific filename by adding /DEPS. This is chosen as a file that
2124 will seldom or never be subject to per-file include_rules.
2125 """
[email protected]2b438d62013-11-14 17:54:142126 # We ignore deps entries on auto-generated directories.
2127 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082128
Daniel Cheng4dcdb6b2017-04-13 08:30:172129 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2130 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2131
2132 added_deps = new_deps.difference(old_deps)
2133
[email protected]2b438d62013-11-14 17:54:142134 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172135 for added_dep in added_deps:
2136 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2137 continue
2138 # Assume that a rule that ends in .h is a rule for a specific file.
2139 if added_dep.endswith('.h'):
2140 results.add(added_dep)
2141 else:
2142 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082143 return results
2144
2145
[email protected]e871964c2013-05-13 14:14:552146def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2147 """When a dependency prefixed with + is added to a DEPS file, we
2148 want to make sure that the change is reviewed by an OWNER of the
2149 target file or directory, to avoid layering violations from being
2150 introduced. This check verifies that this happens.
2151 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172152 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242153
2154 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492155 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242156 for f in input_api.AffectedFiles(include_deletes=False,
2157 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552158 filename = input_api.os_path.basename(f.LocalPath())
2159 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172160 virtual_depended_on_files.update(_CalculateAddedDeps(
2161 input_api.os_path,
2162 '\n'.join(f.OldContents()),
2163 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552164
[email protected]e871964c2013-05-13 14:14:552165 if not virtual_depended_on_files:
2166 return []
2167
2168 if input_api.is_committing:
2169 if input_api.tbr:
2170 return [output_api.PresubmitNotifyResult(
2171 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272172 if input_api.dry_run:
2173 return [output_api.PresubmitNotifyResult(
2174 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552175 if not input_api.change.issue:
2176 return [output_api.PresubmitError(
2177 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402178 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552179 output = output_api.PresubmitError
2180 else:
2181 output = output_api.PresubmitNotifyResult
2182
2183 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502184 owner_email, reviewers = (
2185 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2186 input_api,
2187 owners_db.email_regexp,
2188 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552189
2190 owner_email = owner_email or input_api.change.author_email
2191
[email protected]de4f7d22013-05-23 14:27:462192 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512193 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462194 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552195 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2196 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412197
2198 # We strip the /DEPS part that was added by
2199 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2200 # directory.
2201 def StripDeps(path):
2202 start_deps = path.rfind('/DEPS')
2203 if start_deps != -1:
2204 return path[:start_deps]
2205 else:
2206 return path
2207 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552208 for path in missing_files]
2209
2210 if unapproved_dependencies:
2211 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152212 output('You need LGTM from owners of depends-on paths in DEPS that were '
2213 'modified in this CL:\n %s' %
2214 '\n '.join(sorted(unapproved_dependencies)))]
2215 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2216 output_list.append(output(
2217 'Suggested missing target path OWNERS:\n %s' %
2218 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552219 return output_list
2220
2221 return []
2222
2223
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492224# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402225def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492226 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402227 black_list = (_EXCLUDED_PATHS +
2228 _TEST_CODE_EXCLUDED_PATHS +
2229 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042230 (r"^base[\\/]logging\.h$",
2231 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222232 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042233 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2234 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2235 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122236 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182237 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152238 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032239 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152240 r"^chrome[\\/]chrome_cleaner[\\/].*",
2241 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2242 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042243 r"^chromecast[\\/]",
2244 r"^cloud_print[\\/]",
2245 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482246 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:042247 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:312248 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042249 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462250 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042251 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462252 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042253 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252254 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042255 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2256 r"^courgette[\\/]courgette_tool\.cc$",
2257 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272258 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332259 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042260 r"^ipc[\\/]ipc_logging\.cc$",
2261 r"^native_client_sdk[\\/]",
2262 r"^remoting[\\/]base[\\/]logging\.h$",
2263 r"^remoting[\\/]host[\\/].*",
2264 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332265 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
2266 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042267 r"^tools[\\/]",
2268 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2269 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332270 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402271 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492272 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402273
thomasanderson625d3932017-03-29 07:16:582274 log_info = set([])
2275 printf = set([])
[email protected]85218562013-11-22 07:41:402276
2277 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582278 for _, line in f.ChangedContents():
2279 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2280 log_info.add(f.LocalPath())
2281 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2282 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372283
thomasanderson625d3932017-03-29 07:16:582284 if input_api.re.search(r"\bprintf\(", line):
2285 printf.add(f.LocalPath())
2286 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2287 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402288
2289 if log_info:
2290 return [output_api.PresubmitError(
2291 'These files spam the console log with LOG(INFO):',
2292 items=log_info)]
2293 if printf:
2294 return [output_api.PresubmitError(
2295 'These files spam the console log with printf/fprintf:',
2296 items=printf)]
2297 return []
2298
2299
[email protected]49aa76a2013-12-04 06:59:162300def _CheckForAnonymousVariables(input_api, output_api):
2301 """These types are all expected to hold locks while in scope and
2302 so should never be anonymous (which causes them to be immediately
2303 destroyed)."""
2304 they_who_must_be_named = [
2305 'base::AutoLock',
2306 'base::AutoReset',
2307 'base::AutoUnlock',
2308 'SkAutoAlphaRestore',
2309 'SkAutoBitmapShaderInstall',
2310 'SkAutoBlitterChoose',
2311 'SkAutoBounderCommit',
2312 'SkAutoCallProc',
2313 'SkAutoCanvasRestore',
2314 'SkAutoCommentBlock',
2315 'SkAutoDescriptor',
2316 'SkAutoDisableDirectionCheck',
2317 'SkAutoDisableOvalCheck',
2318 'SkAutoFree',
2319 'SkAutoGlyphCache',
2320 'SkAutoHDC',
2321 'SkAutoLockColors',
2322 'SkAutoLockPixels',
2323 'SkAutoMalloc',
2324 'SkAutoMaskFreeImage',
2325 'SkAutoMutexAcquire',
2326 'SkAutoPathBoundsUpdate',
2327 'SkAutoPDFRelease',
2328 'SkAutoRasterClipValidate',
2329 'SkAutoRef',
2330 'SkAutoTime',
2331 'SkAutoTrace',
2332 'SkAutoUnref',
2333 ]
2334 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2335 # bad: base::AutoLock(lock.get());
2336 # not bad: base::AutoLock lock(lock.get());
2337 bad_pattern = input_api.re.compile(anonymous)
2338 # good: new base::AutoLock(lock.get())
2339 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2340 errors = []
2341
2342 for f in input_api.AffectedFiles():
2343 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2344 continue
2345 for linenum, line in f.ChangedContents():
2346 if bad_pattern.search(line) and not good_pattern.search(line):
2347 errors.append('%s:%d' % (f.LocalPath(), linenum))
2348
2349 if errors:
2350 return [output_api.PresubmitError(
2351 'These lines create anonymous variables that need to be named:',
2352 items=errors)]
2353 return []
2354
2355
Peter Kasting4844e46e2018-02-23 07:27:102356def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532357 # Returns whether |template_str| is of the form <T, U...> for some types T
2358 # and U. Assumes that |template_str| is already in the form <...>.
2359 def HasMoreThanOneArg(template_str):
2360 # Level of <...> nesting.
2361 nesting = 0
2362 for c in template_str:
2363 if c == '<':
2364 nesting += 1
2365 elif c == '>':
2366 nesting -= 1
2367 elif c == ',' and nesting == 1:
2368 return True
2369 return False
2370
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492371 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102372 sources = lambda affected_file: input_api.FilterSourceFile(
2373 affected_file,
2374 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2375 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492376 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552377
2378 # Pattern to capture a single "<...>" block of template arguments. It can
2379 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2380 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2381 # latter would likely require counting that < and > match, which is not
2382 # expressible in regular languages. Should the need arise, one can introduce
2383 # limited counting (matching up to a total number of nesting depth), which
2384 # should cover all practical cases for already a low nesting limit.
2385 template_arg_pattern = (
2386 r'<[^>]*' # Opening block of <.
2387 r'>([^<]*>)?') # Closing block of >.
2388 # Prefix expressing that whatever follows is not already inside a <...>
2389 # block.
2390 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102391 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552392 not_inside_template_arg_pattern
2393 + r'\bstd::unique_ptr'
2394 + template_arg_pattern
2395 + r'\(\)')
2396
2397 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2398 template_arg_no_array_pattern = (
2399 r'<[^>]*[^]]' # Opening block of <.
2400 r'>([^(<]*[^]]>)?') # Closing block of >.
2401 # Prefix saying that what follows is the start of an expression.
2402 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2403 # Suffix saying that what follows are call parentheses with a non-empty list
2404 # of arguments.
2405 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532406 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552407 return_construct_pattern = input_api.re.compile(
2408 start_of_expr_pattern
2409 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532410 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552411 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532412 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552413 + nonempty_arg_list_pattern)
2414
Vaclav Brozek851d9602018-04-04 16:13:052415 problems_constructor = []
2416 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102417 for f in input_api.AffectedSourceFiles(sources):
2418 for line_number, line in f.ChangedContents():
2419 # Disallow:
2420 # return std::unique_ptr<T>(foo);
2421 # bar = std::unique_ptr<T>(foo);
2422 # But allow:
2423 # return std::unique_ptr<T[]>(foo);
2424 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532425 # And also allow cases when the second template argument is present. Those
2426 # cases cannot be handled by std::make_unique:
2427 # return std::unique_ptr<T, U>(foo);
2428 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052429 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532430 return_construct_result = return_construct_pattern.search(line)
2431 if return_construct_result and not HasMoreThanOneArg(
2432 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052433 problems_constructor.append(
2434 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102435 # Disallow:
2436 # std::unique_ptr<T>()
2437 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052438 problems_nullptr.append(
2439 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2440
2441 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162442 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052443 errors.append(output_api.PresubmitError(
2444 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162445 problems_nullptr))
2446 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052447 errors.append(output_api.PresubmitError(
2448 'The following files use explicit std::unique_ptr constructor.'
2449 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162450 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102451 return errors
2452
2453
[email protected]999261d2014-03-03 20:08:082454def _CheckUserActionUpdate(input_api, output_api):
2455 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522456 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082457 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522458 # If actions.xml is already included in the changelist, the PRESUBMIT
2459 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082460 return []
2461
[email protected]999261d2014-03-03 20:08:082462 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2463 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522464 current_actions = None
[email protected]999261d2014-03-03 20:08:082465 for f in input_api.AffectedFiles(file_filter=file_filter):
2466 for line_num, line in f.ChangedContents():
2467 match = input_api.re.search(action_re, line)
2468 if match:
[email protected]2f92dec2014-03-07 19:21:522469 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2470 # loaded only once.
2471 if not current_actions:
2472 with open('tools/metrics/actions/actions.xml') as actions_f:
2473 current_actions = actions_f.read()
2474 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082475 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522476 action = 'name="{0}"'.format(action_name)
2477 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082478 return [output_api.PresubmitPromptWarning(
2479 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522480 'tools/metrics/actions/actions.xml. Please run '
2481 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082482 % (f.LocalPath(), line_num, action_name))]
2483 return []
2484
2485
Daniel Cheng13ca61a882017-08-25 15:11:252486def _ImportJSONCommentEater(input_api):
2487 import sys
2488 sys.path = sys.path + [input_api.os_path.join(
2489 input_api.PresubmitLocalPath(),
2490 'tools', 'json_comment_eater')]
2491 import json_comment_eater
2492 return json_comment_eater
2493
2494
[email protected]99171a92014-06-03 08:44:472495def _GetJSONParseError(input_api, filename, eat_comments=True):
2496 try:
2497 contents = input_api.ReadFile(filename)
2498 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252499 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132500 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472501
2502 input_api.json.loads(contents)
2503 except ValueError as e:
2504 return e
2505 return None
2506
2507
2508def _GetIDLParseError(input_api, filename):
2509 try:
2510 contents = input_api.ReadFile(filename)
2511 idl_schema = input_api.os_path.join(
2512 input_api.PresubmitLocalPath(),
2513 'tools', 'json_schema_compiler', 'idl_schema.py')
2514 process = input_api.subprocess.Popen(
2515 [input_api.python_executable, idl_schema],
2516 stdin=input_api.subprocess.PIPE,
2517 stdout=input_api.subprocess.PIPE,
2518 stderr=input_api.subprocess.PIPE,
2519 universal_newlines=True)
2520 (_, error) = process.communicate(input=contents)
2521 return error or None
2522 except ValueError as e:
2523 return e
2524
2525
2526def _CheckParseErrors(input_api, output_api):
2527 """Check that IDL and JSON files do not contain syntax errors."""
2528 actions = {
2529 '.idl': _GetIDLParseError,
2530 '.json': _GetJSONParseError,
2531 }
[email protected]99171a92014-06-03 08:44:472532 # Most JSON files are preprocessed and support comments, but these do not.
2533 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042534 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472535 ]
2536 # Only run IDL checker on files in these directories.
2537 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042538 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2539 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472540 ]
2541
2542 def get_action(affected_file):
2543 filename = affected_file.LocalPath()
2544 return actions.get(input_api.os_path.splitext(filename)[1])
2545
[email protected]99171a92014-06-03 08:44:472546 def FilterFile(affected_file):
2547 action = get_action(affected_file)
2548 if not action:
2549 return False
2550 path = affected_file.LocalPath()
2551
Sean Kau46e29bc2017-08-28 16:31:162552 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472553 return False
2554
2555 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162556 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472557 return False
2558 return True
2559
2560 results = []
2561 for affected_file in input_api.AffectedFiles(
2562 file_filter=FilterFile, include_deletes=False):
2563 action = get_action(affected_file)
2564 kwargs = {}
2565 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162566 _MatchesFile(input_api, json_no_comments_patterns,
2567 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472568 kwargs['eat_comments'] = False
2569 parse_error = action(input_api,
2570 affected_file.AbsoluteLocalPath(),
2571 **kwargs)
2572 if parse_error:
2573 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2574 (affected_file.LocalPath(), parse_error)))
2575 return results
2576
2577
[email protected]760deea2013-12-10 19:33:492578def _CheckJavaStyle(input_api, output_api):
2579 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472580 import sys
[email protected]760deea2013-12-10 19:33:492581 original_sys_path = sys.path
2582 try:
2583 sys.path = sys.path + [input_api.os_path.join(
2584 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2585 import checkstyle
2586 finally:
2587 # Restore sys.path to what it was before.
2588 sys.path = original_sys_path
2589
2590 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092591 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512592 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492593
2594
Nate Fischerdfd9812e2019-07-18 22:03:002595def _CheckPythonDevilInit(input_api, output_api):
2596 """Checks to make sure devil is initialized correctly in python scripts."""
2597 script_common_initialize_pattern = input_api.re.compile(
2598 r'script_common\.InitializeEnvironment\(')
2599 devil_env_config_initialize = input_api.re.compile(
2600 r'devil_env\.config\.Initialize\(')
2601
2602 errors = []
2603
2604 sources = lambda affected_file: input_api.FilterSourceFile(
2605 affected_file,
2606 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2607 (r'^build[\\/]android[\\/]devil_chromium\.py',
2608 r'^third_party[\\/].*',)),
2609 white_list=[r'.*\.py$'])
2610
2611 for f in input_api.AffectedSourceFiles(sources):
2612 for line_num, line in f.ChangedContents():
2613 if (script_common_initialize_pattern.search(line) or
2614 devil_env_config_initialize.search(line)):
2615 errors.append("%s:%d" % (f.LocalPath(), line_num))
2616
2617 results = []
2618
2619 if errors:
2620 results.append(output_api.PresubmitError(
2621 'Devil initialization should always be done using '
2622 'devil_chromium.Initialize() in the chromium project, to use better '
2623 'defaults for dependencies (ex. up-to-date version of adb).',
2624 errors))
2625
2626 return results
2627
2628
Sean Kau46e29bc2017-08-28 16:31:162629def _MatchesFile(input_api, patterns, path):
2630 for pattern in patterns:
2631 if input_api.re.search(pattern, path):
2632 return True
2633 return False
2634
2635
Daniel Cheng7052cdf2017-11-21 19:23:292636def _GetOwnersFilesToCheckForIpcOwners(input_api):
2637 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172638
Daniel Cheng7052cdf2017-11-21 19:23:292639 Returns:
2640 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2641 contain to cover IPC-related files with noparent reviewer rules.
2642 """
2643 # Whether or not a file affects IPC is (mostly) determined by a simple list
2644 # of filename patterns.
dchenge07de812016-06-20 19:27:172645 file_patterns = [
palmerb19a0932017-01-24 04:00:312646 # Legacy IPC:
dchenge07de812016-06-20 19:27:172647 '*_messages.cc',
2648 '*_messages*.h',
2649 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312650 # Mojo IPC:
dchenge07de812016-06-20 19:27:172651 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472652 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172653 '*_struct_traits*.*',
2654 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312655 '*.typemap',
2656 # Android native IPC:
2657 '*.aidl',
2658 # Blink uses a different file naming convention:
2659 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472660 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172661 '*StructTraits*.*',
2662 '*TypeConverter*.*',
2663 ]
2664
scottmg7a6ed5ba2016-11-04 18:22:042665 # These third_party directories do not contain IPCs, but contain files
2666 # matching the above patterns, which trigger false positives.
2667 exclude_paths = [
2668 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232669 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062670 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292671 'third_party/win_build_output/*',
Clark DuVallfb37334c2019-09-03 18:32:172672 # These aidl files are just used to communicate between class loaders
2673 # running in the same process.
2674 'weblayer/browser/java/org/chromium/weblayer_private/aidl/*',
scottmg7a6ed5ba2016-11-04 18:22:042675 ]
2676
dchenge07de812016-06-20 19:27:172677 # Dictionary mapping an OWNERS file path to Patterns.
2678 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2679 # rules ) to a PatternEntry.
2680 # PatternEntry is a dictionary with two keys:
2681 # - 'files': the files that are matched by this pattern
2682 # - 'rules': the per-file rules needed for this pattern
2683 # For example, if we expect OWNERS file to contain rules for *.mojom and
2684 # *_struct_traits*.*, Patterns might look like this:
2685 # {
2686 # '*.mojom': {
2687 # 'files': ...,
2688 # 'rules': [
2689 # 'per-file *.mojom=set noparent',
2690 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2691 # ],
2692 # },
2693 # '*_struct_traits*.*': {
2694 # 'files': ...,
2695 # 'rules': [
2696 # 'per-file *_struct_traits*.*=set noparent',
2697 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2698 # ],
2699 # },
2700 # }
2701 to_check = {}
2702
Daniel Cheng13ca61a882017-08-25 15:11:252703 def AddPatternToCheck(input_file, pattern):
2704 owners_file = input_api.os_path.join(
2705 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2706 if owners_file not in to_check:
2707 to_check[owners_file] = {}
2708 if pattern not in to_check[owners_file]:
2709 to_check[owners_file][pattern] = {
2710 'files': [],
2711 'rules': [
2712 'per-file %s=set noparent' % pattern,
2713 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2714 ]
2715 }
Vaclav Brozekd5de76a2018-03-17 07:57:502716 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252717
dchenge07de812016-06-20 19:27:172718 # Iterate through the affected files to see what we actually need to check
2719 # for. We should only nag patch authors about per-file rules if a file in that
2720 # directory would match that pattern. If a directory only contains *.mojom
2721 # files and no *_messages*.h files, we should only nag about rules for
2722 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252723 for f in input_api.AffectedFiles(include_deletes=False):
2724 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362725 # affected files for .json, .cc, and .h files which look like they contain
2726 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162727 if (f.LocalPath().endswith('.json') and
2728 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2729 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252730 json_comment_eater = _ImportJSONCommentEater(input_api)
2731 mostly_json_lines = '\n'.join(f.NewContents())
2732 # Comments aren't allowed in strict JSON, so filter them out.
2733 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432734 try:
2735 json_content = input_api.json.loads(json_lines)
2736 except:
2737 # There's another PRESUBMIT check that already verifies that JSON files
2738 # are not invalid, so no need to emit another warning here.
2739 continue
Daniel Cheng13ca61a882017-08-25 15:11:252740 if 'interface_provider_specs' in json_content:
2741 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362742 else:
2743 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2744 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2745 if (manifest_pattern.search(f.LocalPath()) and not
2746 test_manifest_pattern.search(f.LocalPath())):
2747 # We expect all actual service manifest files to contain at least one
2748 # qualified reference to service_manager::Manifest.
2749 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2750 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172751 for pattern in file_patterns:
2752 if input_api.fnmatch.fnmatch(
2753 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042754 skip = False
2755 for exclude in exclude_paths:
2756 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2757 skip = True
2758 break
2759 if skip:
2760 continue
Daniel Cheng13ca61a882017-08-25 15:11:252761 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172762 break
2763
Daniel Cheng7052cdf2017-11-21 19:23:292764 return to_check
2765
2766
2767def _CheckIpcOwners(input_api, output_api):
2768 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2769 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2770
2771 if to_check:
2772 # If there are any OWNERS files to check, there are IPC-related changes in
2773 # this CL. Auto-CC the review list.
2774 output_api.AppendCC('[email protected]')
2775
2776 # Go through the OWNERS files to check, filtering out rules that are already
2777 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172778 for owners_file, patterns in to_check.iteritems():
2779 try:
2780 with file(owners_file) as f:
2781 lines = set(f.read().splitlines())
2782 for entry in patterns.itervalues():
2783 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2784 ]
2785 except IOError:
2786 # No OWNERS file, so all the rules are definitely missing.
2787 continue
2788
2789 # All the remaining lines weren't found in OWNERS files, so emit an error.
2790 errors = []
2791 for owners_file, patterns in to_check.iteritems():
2792 missing_lines = []
2793 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502794 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172795 missing_lines.extend(entry['rules'])
2796 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2797 if missing_lines:
2798 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052799 'Because of the presence of files:\n%s\n\n'
2800 '%s needs the following %d lines added:\n\n%s' %
2801 ('\n'.join(files), owners_file, len(missing_lines),
2802 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172803
2804 results = []
2805 if errors:
vabrf5ce3bf92016-07-11 14:52:412806 if input_api.is_committing:
2807 output = output_api.PresubmitError
2808 else:
2809 output = output_api.PresubmitPromptWarning
2810 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592811 'Found OWNERS files that need to be updated for IPC security ' +
2812 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172813 long_text='\n\n'.join(errors)))
2814
2815 return results
2816
2817
jbriance9e12f162016-11-25 07:57:502818def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312819 """Checks that added or removed lines in non third party affected
2820 header files do not lead to new useless class or struct forward
2821 declaration.
jbriance9e12f162016-11-25 07:57:502822 """
2823 results = []
2824 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2825 input_api.re.MULTILINE)
2826 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2827 input_api.re.MULTILINE)
2828 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312829 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192830 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492831 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312832 continue
2833
jbriance9e12f162016-11-25 07:57:502834 if not f.LocalPath().endswith('.h'):
2835 continue
2836
2837 contents = input_api.ReadFile(f)
2838 fwd_decls = input_api.re.findall(class_pattern, contents)
2839 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2840
2841 useless_fwd_decls = []
2842 for decl in fwd_decls:
2843 count = sum(1 for _ in input_api.re.finditer(
2844 r'\b%s\b' % input_api.re.escape(decl), contents))
2845 if count == 1:
2846 useless_fwd_decls.append(decl)
2847
2848 if not useless_fwd_decls:
2849 continue
2850
2851 for line in f.GenerateScmDiff().splitlines():
2852 if (line.startswith('-') and not line.startswith('--') or
2853 line.startswith('+') and not line.startswith('++')):
2854 for decl in useless_fwd_decls:
2855 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2856 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242857 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502858 (f.LocalPath(), decl)))
2859 useless_fwd_decls.remove(decl)
2860
2861 return results
2862
Jinsong Fan91ebbbd2019-04-16 14:57:172863def _CheckAndroidDebuggableBuild(input_api, output_api):
2864 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2865 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2866 this is a debuggable build of Android.
2867 """
2868 build_type_check_pattern = input_api.re.compile(
2869 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2870
2871 errors = []
2872
2873 sources = lambda affected_file: input_api.FilterSourceFile(
2874 affected_file,
2875 black_list=(_EXCLUDED_PATHS +
2876 _TEST_CODE_EXCLUDED_PATHS +
2877 input_api.DEFAULT_BLACK_LIST +
2878 (r"^android_webview[\\/]support_library[\\/]"
2879 "boundary_interfaces[\\/]",
2880 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2881 r'^third_party[\\/].*',
2882 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2883 r"webview[\\/]chromium[\\/]License.*",)),
2884 white_list=[r'.*\.java$'])
2885
2886 for f in input_api.AffectedSourceFiles(sources):
2887 for line_num, line in f.ChangedContents():
2888 if build_type_check_pattern.search(line):
2889 errors.append("%s:%d" % (f.LocalPath(), line_num))
2890
2891 results = []
2892
2893 if errors:
2894 results.append(output_api.PresubmitPromptWarning(
2895 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2896 ' Please use BuildInfo.isDebugAndroid() instead.',
2897 errors))
2898
2899 return results
jbriance9e12f162016-11-25 07:57:502900
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492901# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292902def _CheckAndroidToastUsage(input_api, output_api):
2903 """Checks that code uses org.chromium.ui.widget.Toast instead of
2904 android.widget.Toast (Chromium Toast doesn't force hardware
2905 acceleration on low-end devices, saving memory).
2906 """
2907 toast_import_pattern = input_api.re.compile(
2908 r'^import android\.widget\.Toast;$')
2909
2910 errors = []
2911
2912 sources = lambda affected_file: input_api.FilterSourceFile(
2913 affected_file,
2914 black_list=(_EXCLUDED_PATHS +
2915 _TEST_CODE_EXCLUDED_PATHS +
2916 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042917 (r'^chromecast[\\/].*',
2918 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492919 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292920
2921 for f in input_api.AffectedSourceFiles(sources):
2922 for line_num, line in f.ChangedContents():
2923 if toast_import_pattern.search(line):
2924 errors.append("%s:%d" % (f.LocalPath(), line_num))
2925
2926 results = []
2927
2928 if errors:
2929 results.append(output_api.PresubmitError(
2930 'android.widget.Toast usage is detected. Android toasts use hardware'
2931 ' acceleration, and can be\ncostly on low-end devices. Please use'
2932 ' org.chromium.ui.widget.Toast instead.\n'
2933 'Contact [email protected] if you have any questions.',
2934 errors))
2935
2936 return results
2937
2938
dgnaa68d5e2015-06-10 10:08:222939def _CheckAndroidCrLogUsage(input_api, output_api):
2940 """Checks that new logs using org.chromium.base.Log:
2941 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512942 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222943 """
pkotwicza1dd0b002016-05-16 14:41:042944
torne89540622017-03-24 19:41:302945 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042946 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302947 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042948 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302949 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042950 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2951 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092952 # The customtabs_benchmark is a small app that does not depend on Chromium
2953 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042954 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042955 ]
2956
dgnaa68d5e2015-06-10 10:08:222957 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122958 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2959 class_in_base_pattern = input_api.re.compile(
2960 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2961 has_some_log_import_pattern = input_api.re.compile(
2962 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222963 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122964 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222965 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512966 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222967 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222968
Vincent Scheib16d7b272015-09-15 18:09:072969 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222970 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492971 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042972 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122973
dgnaa68d5e2015-06-10 10:08:222974 tag_decl_errors = []
2975 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122976 tag_errors = []
dgn38736db2015-09-18 19:20:512977 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122978 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222979
2980 for f in input_api.AffectedSourceFiles(sources):
2981 file_content = input_api.ReadFile(f)
2982 has_modified_logs = False
2983
2984 # Per line checks
dgn87d9fb62015-06-12 09:15:122985 if (cr_log_import_pattern.search(file_content) or
2986 (class_in_base_pattern.search(file_content) and
2987 not has_some_log_import_pattern.search(file_content))):
2988 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222989 for line_num, line in f.ChangedContents():
2990
2991 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122992 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222993 if match:
2994 has_modified_logs = True
2995
2996 # Make sure it uses "TAG"
2997 if not match.group('tag') == 'TAG':
2998 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122999 else:
3000 # Report non cr Log function calls in changed lines
3001 for line_num, line in f.ChangedContents():
3002 if log_call_pattern.search(line):
3003 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223004
3005 # Per file checks
3006 if has_modified_logs:
3007 # Make sure the tag is using the "cr" prefix and is not too long
3008 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513009 tag_name = match.group('name') if match else None
3010 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223011 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513012 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223013 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513014 elif '.' in tag_name:
3015 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223016
3017 results = []
3018 if tag_decl_errors:
3019 results.append(output_api.PresubmitPromptWarning(
3020 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513021 '"private static final String TAG = "<package tag>".\n'
3022 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223023 tag_decl_errors))
3024
3025 if tag_length_errors:
3026 results.append(output_api.PresubmitError(
3027 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513028 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223029 tag_length_errors))
3030
3031 if tag_errors:
3032 results.append(output_api.PresubmitPromptWarning(
3033 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3034 tag_errors))
3035
dgn87d9fb62015-06-12 09:15:123036 if util_log_errors:
dgn4401aa52015-04-29 16:26:173037 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123038 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3039 util_log_errors))
3040
dgn38736db2015-09-18 19:20:513041 if tag_with_dot_errors:
3042 results.append(output_api.PresubmitPromptWarning(
3043 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3044 tag_with_dot_errors))
3045
dgn4401aa52015-04-29 16:26:173046 return results
3047
3048
Yoland Yanb92fa522017-08-28 17:37:063049def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3050 """Checks that junit.framework.* is no longer used."""
3051 deprecated_junit_framework_pattern = input_api.re.compile(
3052 r'^import junit\.framework\..*;',
3053 input_api.re.MULTILINE)
3054 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493055 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063056 errors = []
3057 for f in input_api.AffectedFiles(sources):
3058 for line_num, line in f.ChangedContents():
3059 if deprecated_junit_framework_pattern.search(line):
3060 errors.append("%s:%d" % (f.LocalPath(), line_num))
3061
3062 results = []
3063 if errors:
3064 results.append(output_api.PresubmitError(
3065 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3066 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3067 ' if you have any question.', errors))
3068 return results
3069
3070
3071def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3072 """Checks that if new Java test classes have inheritance.
3073 Either the new test class is JUnit3 test or it is a JUnit4 test class
3074 with a base class, either case is undesirable.
3075 """
3076 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3077
3078 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493079 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063080 errors = []
3081 for f in input_api.AffectedFiles(sources):
3082 if not f.OldContents():
3083 class_declaration_start_flag = False
3084 for line_num, line in f.ChangedContents():
3085 if class_declaration_pattern.search(line):
3086 class_declaration_start_flag = True
3087 if class_declaration_start_flag and ' extends ' in line:
3088 errors.append('%s:%d' % (f.LocalPath(), line_num))
3089 if '{' in line:
3090 class_declaration_start_flag = False
3091
3092 results = []
3093 if errors:
3094 results.append(output_api.PresubmitPromptWarning(
3095 'The newly created files include Test classes that inherits from base'
3096 ' class. Please do not use inheritance in JUnit4 tests or add new'
3097 ' JUnit3 tests. Contact [email protected] if you have any'
3098 ' questions.', errors))
3099 return results
3100
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203101
yolandyan45001472016-12-21 21:12:423102def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3103 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3104 deprecated_annotation_import_pattern = input_api.re.compile(
3105 r'^import android\.test\.suitebuilder\.annotation\..*;',
3106 input_api.re.MULTILINE)
3107 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493108 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423109 errors = []
3110 for f in input_api.AffectedFiles(sources):
3111 for line_num, line in f.ChangedContents():
3112 if deprecated_annotation_import_pattern.search(line):
3113 errors.append("%s:%d" % (f.LocalPath(), line_num))
3114
3115 results = []
3116 if errors:
3117 results.append(output_api.PresubmitError(
3118 'Annotations in android.test.suitebuilder.annotation have been'
3119 ' deprecated since API level 24. Please use android.support.test.filters'
3120 ' from //third_party/android_support_test_runner:runner_java instead.'
3121 ' Contact [email protected] if you have any questions.', errors))
3122 return results
3123
3124
agrieve7b6479d82015-10-07 14:24:223125def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3126 """Checks if MDPI assets are placed in a correct directory."""
3127 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3128 ('/res/drawable/' in f.LocalPath() or
3129 '/res/drawable-ldrtl/' in f.LocalPath()))
3130 errors = []
3131 for f in input_api.AffectedFiles(include_deletes=False,
3132 file_filter=file_filter):
3133 errors.append(' %s' % f.LocalPath())
3134
3135 results = []
3136 if errors:
3137 results.append(output_api.PresubmitError(
3138 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3139 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3140 '/res/drawable-ldrtl/.\n'
3141 'Contact [email protected] if you have questions.', errors))
3142 return results
3143
3144
Nate Fischer535972b2017-09-16 01:06:183145def _CheckAndroidWebkitImports(input_api, output_api):
3146 """Checks that code uses org.chromium.base.Callback instead of
3147 android.widget.ValueCallback except in the WebView glue layer.
3148 """
3149 valuecallback_import_pattern = input_api.re.compile(
3150 r'^import android\.webkit\.ValueCallback;$')
3151
3152 errors = []
3153
3154 sources = lambda affected_file: input_api.FilterSourceFile(
3155 affected_file,
3156 black_list=(_EXCLUDED_PATHS +
3157 _TEST_CODE_EXCLUDED_PATHS +
3158 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043159 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493160 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183161
3162 for f in input_api.AffectedSourceFiles(sources):
3163 for line_num, line in f.ChangedContents():
3164 if valuecallback_import_pattern.search(line):
3165 errors.append("%s:%d" % (f.LocalPath(), line_num))
3166
3167 results = []
3168
3169 if errors:
3170 results.append(output_api.PresubmitError(
3171 'android.webkit.ValueCallback usage is detected outside of the glue'
3172 ' layer. To stay compatible with the support library, android.webkit.*'
3173 ' classes should only be used inside the glue layer and'
3174 ' org.chromium.base.Callback should be used instead.',
3175 errors))
3176
3177 return results
3178
3179
Becky Zhou7c69b50992018-12-10 19:37:573180def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3181 """Checks Android XML styles """
3182 import sys
3183 original_sys_path = sys.path
3184 try:
3185 sys.path = sys.path + [input_api.os_path.join(
3186 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3187 import checkxmlstyle
3188 finally:
3189 # Restore sys.path to what it was before.
3190 sys.path = original_sys_path
3191
3192 if is_check_on_upload:
3193 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3194 else:
3195 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3196
3197
agrievef32bcc72016-04-04 14:57:403198class PydepsChecker(object):
3199 def __init__(self, input_api, pydeps_files):
3200 self._file_cache = {}
3201 self._input_api = input_api
3202 self._pydeps_files = pydeps_files
3203
3204 def _LoadFile(self, path):
3205 """Returns the list of paths within a .pydeps file relative to //."""
3206 if path not in self._file_cache:
3207 with open(path) as f:
3208 self._file_cache[path] = f.read()
3209 return self._file_cache[path]
3210
3211 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3212 """Returns an interable of paths within the .pydep, relativized to //."""
3213 os_path = self._input_api.os_path
3214 pydeps_dir = os_path.dirname(pydeps_path)
3215 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3216 if not l.startswith('*'))
3217 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3218
3219 def _CreateFilesToPydepsMap(self):
3220 """Returns a map of local_path -> list_of_pydeps."""
3221 ret = {}
3222 for pydep_local_path in self._pydeps_files:
3223 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3224 ret.setdefault(path, []).append(pydep_local_path)
3225 return ret
3226
3227 def ComputeAffectedPydeps(self):
3228 """Returns an iterable of .pydeps files that might need regenerating."""
3229 affected_pydeps = set()
3230 file_to_pydeps_map = None
3231 for f in self._input_api.AffectedFiles(include_deletes=True):
3232 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463233 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3234 # subrepositories. We can't figure out which files change, so re-check
3235 # all files.
3236 # Changes to print_python_deps.py affect all .pydeps.
3237 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403238 return self._pydeps_files
3239 elif local_path.endswith('.pydeps'):
3240 if local_path in self._pydeps_files:
3241 affected_pydeps.add(local_path)
3242 elif local_path.endswith('.py'):
3243 if file_to_pydeps_map is None:
3244 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3245 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3246 return affected_pydeps
3247
3248 def DetermineIfStale(self, pydeps_path):
3249 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413250 import difflib
John Budorick47ca3fe2018-02-10 00:53:103251 import os
3252
agrievef32bcc72016-04-04 14:57:403253 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3254 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103255 env = dict(os.environ)
3256 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403257 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103258 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413259 old_contents = old_pydeps_data[2:]
3260 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403261 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413262 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403263
3264
Tibor Goldschwendt360793f72019-06-25 18:23:493265def _ParseGclientArgs():
3266 args = {}
3267 with open('build/config/gclient_args.gni', 'r') as f:
3268 for line in f:
3269 line = line.strip()
3270 if not line or line.startswith('#'):
3271 continue
3272 attribute, value = line.split('=')
3273 args[attribute.strip()] = value.strip()
3274 return args
3275
3276
agrievef32bcc72016-04-04 14:57:403277def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3278 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403279 # This check is for Python dependency lists (.pydeps files), and involves
3280 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3281 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283282 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003283 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493284 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403285 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3286 results = []
3287 # First, check for new / deleted .pydeps.
3288 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033289 # Check whether we are running the presubmit check for a file in src.
3290 # f.LocalPath is relative to repo (src, or internal repo).
3291 # os_path.exists is relative to src repo.
3292 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3293 # to src and we can conclude that the pydeps is in src.
3294 if input_api.os_path.exists(f.LocalPath()):
3295 if f.LocalPath().endswith('.pydeps'):
3296 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3297 results.append(output_api.PresubmitError(
3298 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3299 'remove %s' % f.LocalPath()))
3300 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3301 results.append(output_api.PresubmitError(
3302 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3303 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403304
3305 if results:
3306 return results
3307
3308 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3309
3310 for pydep_path in checker.ComputeAffectedPydeps():
3311 try:
phajdan.jr0d9878552016-11-04 10:49:413312 result = checker.DetermineIfStale(pydep_path)
3313 if result:
3314 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403315 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413316 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3317 'To regenerate, run:\n\n %s' %
3318 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403319 except input_api.subprocess.CalledProcessError as error:
3320 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3321 long_text=error.output)]
3322
3323 return results
3324
3325
glidere61efad2015-02-18 17:39:433326def _CheckSingletonInHeaders(input_api, output_api):
3327 """Checks to make sure no header files have |Singleton<|."""
3328 def FileFilter(affected_file):
3329 # It's ok for base/memory/singleton.h to have |Singleton<|.
3330 black_list = (_EXCLUDED_PATHS +
3331 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043332 (r"^base[\\/]memory[\\/]singleton\.h$",
3333 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473334 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433335 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3336
sergeyu34d21222015-09-16 00:11:443337 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433338 files = []
3339 for f in input_api.AffectedSourceFiles(FileFilter):
3340 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3341 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3342 contents = input_api.ReadFile(f)
3343 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243344 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433345 pattern.search(line)):
3346 files.append(f)
3347 break
3348
3349 if files:
yolandyandaabc6d2016-04-18 18:29:393350 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443351 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433352 'Please move them to an appropriate source file so that the ' +
3353 'template gets instantiated in a single compilation unit.',
3354 files) ]
3355 return []
3356
3357
[email protected]fd20b902014-05-09 02:14:533358_DEPRECATED_CSS = [
3359 # Values
3360 ( "-webkit-box", "flex" ),
3361 ( "-webkit-inline-box", "inline-flex" ),
3362 ( "-webkit-flex", "flex" ),
3363 ( "-webkit-inline-flex", "inline-flex" ),
3364 ( "-webkit-min-content", "min-content" ),
3365 ( "-webkit-max-content", "max-content" ),
3366
3367 # Properties
3368 ( "-webkit-background-clip", "background-clip" ),
3369 ( "-webkit-background-origin", "background-origin" ),
3370 ( "-webkit-background-size", "background-size" ),
3371 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443372 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533373
3374 # Functions
3375 ( "-webkit-gradient", "gradient" ),
3376 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3377 ( "-webkit-linear-gradient", "linear-gradient" ),
3378 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3379 ( "-webkit-radial-gradient", "radial-gradient" ),
3380 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3381]
3382
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203383
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493384# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243385def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533386 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253387 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343388 documentation and iOS CSS for dom distiller
3389 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253390 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533391 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493392 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253393 black_list = (_EXCLUDED_PATHS +
3394 _TEST_CODE_EXCLUDED_PATHS +
3395 input_api.DEFAULT_BLACK_LIST +
3396 (r"^chrome/common/extensions/docs",
3397 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343398 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443399 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253400 r"^native_client_sdk"))
3401 file_filter = lambda f: input_api.FilterSourceFile(
3402 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533403 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3404 for line_num, line in fpath.ChangedContents():
3405 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023406 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533407 results.append(output_api.PresubmitError(
3408 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3409 (fpath.LocalPath(), line_num, deprecated_value, value)))
3410 return results
3411
mohan.reddyf21db962014-10-16 12:26:473412
rlanday6802cf632017-05-30 17:48:363413def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363414 bad_files = {}
3415 for f in input_api.AffectedFiles(include_deletes=False):
3416 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493417 not f.LocalPath().startswith('third_party/blink') and
3418 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363419 continue
3420
Daniel Bratell65b033262019-04-23 08:17:063421 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363422 continue
3423
Vaclav Brozekd5de76a2018-03-17 07:57:503424 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363425 if "#include" in line and "../" in line]
3426 if not relative_includes:
3427 continue
3428 bad_files[f.LocalPath()] = relative_includes
3429
3430 if not bad_files:
3431 return []
3432
3433 error_descriptions = []
3434 for file_path, bad_lines in bad_files.iteritems():
3435 error_description = file_path
3436 for line in bad_lines:
3437 error_description += '\n ' + line
3438 error_descriptions.append(error_description)
3439
3440 results = []
3441 results.append(output_api.PresubmitError(
3442 'You added one or more relative #include paths (including "../").\n'
3443 'These shouldn\'t be used because they can be used to include headers\n'
3444 'from code that\'s not correctly specified as a dependency in the\n'
3445 'relevant BUILD.gn file(s).',
3446 error_descriptions))
3447
3448 return results
3449
Takeshi Yoshinoe387aa32017-08-02 13:16:133450
Daniel Bratell65b033262019-04-23 08:17:063451def _CheckForCcIncludes(input_api, output_api):
3452 """Check that nobody tries to include a cc file. It's a relatively
3453 common error which results in duplicate symbols in object
3454 files. This may not always break the build until someone later gets
3455 very confusing linking errors."""
3456 results = []
3457 for f in input_api.AffectedFiles(include_deletes=False):
3458 # We let third_party code do whatever it wants
3459 if (f.LocalPath().startswith('third_party') and
3460 not f.LocalPath().startswith('third_party/blink') and
3461 not f.LocalPath().startswith('third_party\\blink')):
3462 continue
3463
3464 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3465 continue
3466
3467 for _, line in f.ChangedContents():
3468 if line.startswith('#include "'):
3469 included_file = line.split('"')[1]
3470 if _IsCPlusPlusFile(input_api, included_file):
3471 # The most common naming for external files with C++ code,
3472 # apart from standard headers, is to call them foo.inc, but
3473 # Chromium sometimes uses foo-inc.cc so allow that as well.
3474 if not included_file.endswith(('.h', '-inc.cc')):
3475 results.append(output_api.PresubmitError(
3476 'Only header files or .inc files should be included in other\n'
3477 'C++ files. Compiling the contents of a cc file more than once\n'
3478 'will cause duplicate information in the build which may later\n'
3479 'result in strange link_errors.\n' +
3480 f.LocalPath() + ':\n ' +
3481 line))
3482
3483 return results
3484
3485
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203486def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3487 if not isinstance(key, ast.Str):
3488 return 'Key at line %d must be a string literal' % key.lineno
3489 if not isinstance(value, ast.Dict):
3490 return 'Value at line %d must be a dict' % value.lineno
3491 if len(value.keys) != 1:
3492 return 'Dict at line %d must have single entry' % value.lineno
3493 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3494 return (
3495 'Entry at line %d must have a string literal \'filepath\' as key' %
3496 value.lineno)
3497 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133498
Takeshi Yoshinoe387aa32017-08-02 13:16:133499
Sergey Ulanov4af16052018-11-08 02:41:463500def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203501 if not isinstance(key, ast.Str):
3502 return 'Key at line %d must be a string literal' % key.lineno
3503 if not isinstance(value, ast.List):
3504 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463505 for element in value.elts:
3506 if not isinstance(element, ast.Str):
3507 return 'Watchlist elements on line %d is not a string' % key.lineno
3508 if not email_regex.match(element.s):
3509 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3510 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203511 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133512
Takeshi Yoshinoe387aa32017-08-02 13:16:133513
Sergey Ulanov4af16052018-11-08 02:41:463514def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203515 mismatch_template = (
3516 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3517 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133518
Sergey Ulanov4af16052018-11-08 02:41:463519 email_regex = input_api.re.compile(
3520 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3521
3522 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203523 i = 0
3524 last_key = ''
3525 while True:
3526 if i >= len(wd_dict.keys):
3527 if i >= len(w_dict.keys):
3528 return None
3529 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3530 elif i >= len(w_dict.keys):
3531 return (
3532 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133533
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203534 wd_key = wd_dict.keys[i]
3535 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133536
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203537 result = _CheckWatchlistDefinitionsEntrySyntax(
3538 wd_key, wd_dict.values[i], ast)
3539 if result is not None:
3540 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133541
Sergey Ulanov4af16052018-11-08 02:41:463542 result = _CheckWatchlistsEntrySyntax(
3543 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203544 if result is not None:
3545 return 'Bad entry in WATCHLISTS dict: %s' % result
3546
3547 if wd_key.s != w_key.s:
3548 return mismatch_template % (
3549 '%s at line %d' % (wd_key.s, wd_key.lineno),
3550 '%s at line %d' % (w_key.s, w_key.lineno))
3551
3552 if wd_key.s < last_key:
3553 return (
3554 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3555 (wd_key.lineno, w_key.lineno))
3556 last_key = wd_key.s
3557
3558 i = i + 1
3559
3560
Sergey Ulanov4af16052018-11-08 02:41:463561def _CheckWATCHLISTSSyntax(expression, input_api):
3562 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203563 if not isinstance(expression, ast.Expression):
3564 return 'WATCHLISTS file must contain a valid expression'
3565 dictionary = expression.body
3566 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3567 return 'WATCHLISTS file must have single dict with exactly two entries'
3568
3569 first_key = dictionary.keys[0]
3570 first_value = dictionary.values[0]
3571 second_key = dictionary.keys[1]
3572 second_value = dictionary.values[1]
3573
3574 if (not isinstance(first_key, ast.Str) or
3575 first_key.s != 'WATCHLIST_DEFINITIONS' or
3576 not isinstance(first_value, ast.Dict)):
3577 return (
3578 'The first entry of the dict in WATCHLISTS file must be '
3579 'WATCHLIST_DEFINITIONS dict')
3580
3581 if (not isinstance(second_key, ast.Str) or
3582 second_key.s != 'WATCHLISTS' or
3583 not isinstance(second_value, ast.Dict)):
3584 return (
3585 'The second entry of the dict in WATCHLISTS file must be '
3586 'WATCHLISTS dict')
3587
Sergey Ulanov4af16052018-11-08 02:41:463588 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133589
3590
3591def _CheckWATCHLISTS(input_api, output_api):
3592 for f in input_api.AffectedFiles(include_deletes=False):
3593 if f.LocalPath() == 'WATCHLISTS':
3594 contents = input_api.ReadFile(f, 'r')
3595
3596 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203597 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133598 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203599 # Get an AST tree for it and scan the tree for detailed style checking.
3600 expression = input_api.ast.parse(
3601 contents, filename='WATCHLISTS', mode='eval')
3602 except ValueError as e:
3603 return [output_api.PresubmitError(
3604 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3605 except SyntaxError as e:
3606 return [output_api.PresubmitError(
3607 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3608 except TypeError as e:
3609 return [output_api.PresubmitError(
3610 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133611
Sergey Ulanov4af16052018-11-08 02:41:463612 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203613 if result is not None:
3614 return [output_api.PresubmitError(result)]
3615 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133616
3617 return []
3618
3619
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193620def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3621 """Checks that newly added header files have corresponding GN changes.
3622 Note that this is only a heuristic. To be precise, run script:
3623 build/check_gn_headers.py.
3624 """
3625
3626 def headers(f):
3627 return input_api.FilterSourceFile(
3628 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3629
3630 new_headers = []
3631 for f in input_api.AffectedSourceFiles(headers):
3632 if f.Action() != 'A':
3633 continue
3634 new_headers.append(f.LocalPath())
3635
3636 def gn_files(f):
3637 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3638
3639 all_gn_changed_contents = ''
3640 for f in input_api.AffectedSourceFiles(gn_files):
3641 for _, line in f.ChangedContents():
3642 all_gn_changed_contents += line
3643
3644 problems = []
3645 for header in new_headers:
3646 basename = input_api.os_path.basename(header)
3647 if basename not in all_gn_changed_contents:
3648 problems.append(header)
3649
3650 if problems:
3651 return [output_api.PresubmitPromptWarning(
3652 'Missing GN changes for new header files', items=sorted(problems),
3653 long_text='Please double check whether newly added header files need '
3654 'corresponding changes in gn or gni files.\nThis checking is only a '
3655 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3656 'Read https://crbug.com/661774 for more info.')]
3657 return []
3658
3659
Michael Giuffridad3bc8672018-10-25 22:48:023660def _CheckCorrectProductNameInMessages(input_api, output_api):
3661 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3662
3663 This assumes we won't intentionally reference one product from the other
3664 product.
3665 """
3666 all_problems = []
3667 test_cases = [{
3668 "filename_postfix": "google_chrome_strings.grd",
3669 "correct_name": "Chrome",
3670 "incorrect_name": "Chromium",
3671 }, {
3672 "filename_postfix": "chromium_strings.grd",
3673 "correct_name": "Chromium",
3674 "incorrect_name": "Chrome",
3675 }]
3676
3677 for test_case in test_cases:
3678 problems = []
3679 filename_filter = lambda x: x.LocalPath().endswith(
3680 test_case["filename_postfix"])
3681
3682 # Check each new line. Can yield false positives in multiline comments, but
3683 # easier than trying to parse the XML because messages can have nested
3684 # children, and associating message elements with affected lines is hard.
3685 for f in input_api.AffectedSourceFiles(filename_filter):
3686 for line_num, line in f.ChangedContents():
3687 if "<message" in line or "<!--" in line or "-->" in line:
3688 continue
3689 if test_case["incorrect_name"] in line:
3690 problems.append(
3691 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3692
3693 if problems:
3694 message = (
3695 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3696 % (test_case["correct_name"], test_case["correct_name"],
3697 test_case["incorrect_name"]))
3698 all_problems.append(
3699 output_api.PresubmitPromptWarning(message, items=problems))
3700
3701 return all_problems
3702
3703
Dirk Pranke3c18a382019-03-15 01:07:513704def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3705 # TODO(crbug.com/941824): We need to make sure the entries in
3706 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3707 # so that users of //buildtools in other projects get the same tooling
3708 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3709 # support to gclient, we can eliminate the duplication and delete
3710 # this presubmit check.
3711
3712 # Update this regexp if new revisions are added to the files.
3713 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013714 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513715
3716 # If a user is changing one revision, they need to change the same
3717 # line in both files. This means that any given change should contain
3718 # exactly the same list of changed lines that match the regexps. The
3719 # replace(' ', '') call allows us to ignore whitespace changes to the
3720 # lines. The 'long_text' parameter to the error will contain the
3721 # list of changed lines in both files, which should make it easy enough
3722 # to spot the error without going overboard in this implementation.
3723 revs_changes = {
3724 'DEPS': {},
3725 'buildtools/DEPS': {},
3726 }
3727 long_text = ''
3728
3729 for f in input_api.AffectedFiles(
3730 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3731 for line_num, line in f.ChangedContents():
3732 if rev_regexp.search(line):
3733 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3734 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3735
3736 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3737 return [output_api.PresubmitError(
3738 'Change buildtools revisions in sync in both //DEPS and '
3739 '//buildtools/DEPS.', long_text=long_text + '\n')]
3740 else:
3741 return []
3742
3743
Daniel Bratell93eb6c62019-04-29 20:13:363744def _CheckForTooLargeFiles(input_api, output_api):
3745 """Avoid large files, especially binary files, in the repository since
3746 git doesn't scale well for those. They will be in everyone's repo
3747 clones forever, forever making Chromium slower to clone and work
3748 with."""
3749
3750 # Uploading files to cloud storage is not trivial so we don't want
3751 # to set the limit too low, but the upper limit for "normal" large
3752 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3753 # anything over 20 MB is exceptional.
3754 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3755
3756 too_large_files = []
3757 for f in input_api.AffectedFiles():
3758 # Check both added and modified files (but not deleted files).
3759 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:383760 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:363761 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3762 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3763
3764 if too_large_files:
3765 message = (
3766 'Do not commit large files to git since git scales badly for those.\n' +
3767 'Instead put the large files in cloud storage and use DEPS to\n' +
3768 'fetch them.\n' + '\n'.join(too_large_files)
3769 )
3770 return [output_api.PresubmitError(
3771 'Too large files found in commit', long_text=message + '\n')]
3772 else:
3773 return []
3774
Max Morozb47503b2019-08-08 21:03:273775
3776def _CheckFuzzTargets(input_api, output_api):
3777 """Checks specific for fuzz target sources."""
3778 EXPORTED_SYMBOLS = [
3779 'LLVMFuzzerInitialize',
3780 'LLVMFuzzerCustomMutator',
3781 'LLVMFuzzerCustomCrossOver',
3782 'LLVMFuzzerMutate',
3783 ]
3784
3785 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
3786
3787 def FilterFile(affected_file):
3788 """Ignore libFuzzer source code."""
3789 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
3790 black_list = r"^third_party[\\/]libFuzzer"
3791
3792 return input_api.FilterSourceFile(
3793 affected_file,
3794 white_list=[white_list],
3795 black_list=[black_list])
3796
3797 files_with_missing_header = []
3798 for f in input_api.AffectedSourceFiles(FilterFile):
3799 contents = input_api.ReadFile(f, 'r')
3800 if REQUIRED_HEADER in contents:
3801 continue
3802
3803 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
3804 files_with_missing_header.append(f.LocalPath())
3805
3806 if not files_with_missing_header:
3807 return []
3808
3809 long_text = (
3810 'If you define any of the libFuzzer optional functions (%s), it is '
3811 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
3812 'work incorrectly on Mac (crbug.com/687076).\nNote that '
3813 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
3814 'to access command line arguments passed to the fuzzer. Instead, prefer '
3815 'static initialization and shared resources as documented in '
3816 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
3817 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
3818 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
3819 )
3820
3821 return [output_api.PresubmitPromptWarning(
3822 message="Missing '%s' in:" % REQUIRED_HEADER,
3823 items=files_with_missing_header,
3824 long_text=long_text)]
3825
3826
dgnaa68d5e2015-06-10 10:08:223827def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573828 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223829 results = []
dgnaa68d5e2015-06-10 10:08:223830 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173831 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223832 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293833 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063834 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3835 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423836 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183837 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573838 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3839 return results
3840
3841def _AndroidSpecificOnCommitChecks(input_api, output_api):
3842 """Groups commit checks that target android code."""
3843 results = []
3844 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223845 return results
3846
3847
[email protected]22c9bd72011-03-27 16:47:393848def _CommonChecks(input_api, output_api):
3849 """Checks common to both upload and commit."""
3850 results = []
3851 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383852 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543853 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083854
3855 author = input_api.change.author_email
3856 if author and author not in _KNOWN_ROBOTS:
3857 results.extend(
3858 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3859
[email protected]55459852011-08-10 15:17:193860 results.extend(
[email protected]760deea2013-12-10 19:33:493861 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233862 results.extend(
3863 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543864 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183865 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343866 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523867 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223868 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443869 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593870 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063871 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123872 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183873 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223874 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303875 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493876 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033877 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493878 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443879 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273880 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073881 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543882 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443883 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393884 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553885 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043886 results.extend(
3887 input_api.canned_checks.CheckChangeHasNoTabs(
3888 input_api,
3889 output_api,
3890 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403891 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163892 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083893 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243894 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473895 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043896 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053897 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143898 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233899 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433900 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403901 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153902 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173903 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503904 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363905 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063906 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133907 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433908 results.extend(input_api.RunTests(
3909 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143910 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023911 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513912 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:363913 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:003914 results.extend(_CheckPythonDevilInit(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243915
Vaclav Brozekcdc7defb2018-03-20 09:54:353916 for f in input_api.AffectedFiles():
3917 path, name = input_api.os_path.split(f.LocalPath())
3918 if name == 'PRESUBMIT.py':
3919 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003920 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3921 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073922 # The PRESUBMIT.py file (and the directory containing it) might
3923 # have been affected by being moved or removed, so only try to
3924 # run the tests if they still exist.
3925 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3926 input_api, output_api, full_path,
3927 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393928 return results
[email protected]1f7b4172010-01-28 01:17:343929
[email protected]b337cb5b2011-01-23 21:24:053930
[email protected]b8079ae4a2012-12-05 19:56:493931def _CheckPatchFiles(input_api, output_api):
3932 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3933 if f.LocalPath().endswith(('.orig', '.rej'))]
3934 if problems:
3935 return [output_api.PresubmitError(
3936 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033937 else:
3938 return []
[email protected]b8079ae4a2012-12-05 19:56:493939
3940
Kent Tamura5a8755d2017-06-29 23:37:073941def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213942 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3943 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3944 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073945 include_re = input_api.re.compile(
3946 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3947 extension_re = input_api.re.compile(r'\.[a-z]+$')
3948 errors = []
3949 for f in input_api.AffectedFiles():
3950 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3951 continue
3952 found_line_number = None
3953 found_macro = None
3954 for line_num, line in f.ChangedContents():
3955 match = macro_re.search(line)
3956 if match:
3957 found_line_number = line_num
3958 found_macro = match.group(2)
3959 break
3960 if not found_line_number:
3961 continue
3962
3963 found_include = False
3964 for line in f.NewContents():
3965 if include_re.search(line):
3966 found_include = True
3967 break
3968 if found_include:
3969 continue
3970
3971 if not f.LocalPath().endswith('.h'):
3972 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3973 try:
3974 content = input_api.ReadFile(primary_header_path, 'r')
3975 if include_re.search(content):
3976 continue
3977 except IOError:
3978 pass
3979 errors.append('%s:%d %s macro is used without including build/'
3980 'build_config.h.'
3981 % (f.LocalPath(), found_line_number, found_macro))
3982 if errors:
3983 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3984 return []
3985
3986
[email protected]b00342e7f2013-03-26 16:21:543987def _DidYouMeanOSMacro(bad_macro):
3988 try:
3989 return {'A': 'OS_ANDROID',
3990 'B': 'OS_BSD',
3991 'C': 'OS_CHROMEOS',
3992 'F': 'OS_FREEBSD',
3993 'L': 'OS_LINUX',
3994 'M': 'OS_MACOSX',
3995 'N': 'OS_NACL',
3996 'O': 'OS_OPENBSD',
3997 'P': 'OS_POSIX',
3998 'S': 'OS_SOLARIS',
3999 'W': 'OS_WIN'}[bad_macro[3].upper()]
4000 except KeyError:
4001 return ''
4002
4003
4004def _CheckForInvalidOSMacrosInFile(input_api, f):
4005 """Check for sensible looking, totally invalid OS macros."""
4006 preprocessor_statement = input_api.re.compile(r'^\s*#')
4007 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4008 results = []
4009 for lnum, line in f.ChangedContents():
4010 if preprocessor_statement.search(line):
4011 for match in os_macro.finditer(line):
4012 if not match.group(1) in _VALID_OS_MACROS:
4013 good = _DidYouMeanOSMacro(match.group(1))
4014 did_you_mean = ' (did you mean %s?)' % good if good else ''
4015 results.append(' %s:%d %s%s' % (f.LocalPath(),
4016 lnum,
4017 match.group(1),
4018 did_you_mean))
4019 return results
4020
4021
4022def _CheckForInvalidOSMacros(input_api, output_api):
4023 """Check all affected files for invalid OS macros."""
4024 bad_macros = []
tzik3f295992018-12-04 20:32:234025 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474026 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544027 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4028
4029 if not bad_macros:
4030 return []
4031
4032 return [output_api.PresubmitError(
4033 'Possibly invalid OS macro[s] found. Please fix your code\n'
4034 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4035
lliabraa35bab3932014-10-01 12:16:444036
4037def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4038 """Check all affected files for invalid "if defined" macros."""
4039 ALWAYS_DEFINED_MACROS = (
4040 "TARGET_CPU_PPC",
4041 "TARGET_CPU_PPC64",
4042 "TARGET_CPU_68K",
4043 "TARGET_CPU_X86",
4044 "TARGET_CPU_ARM",
4045 "TARGET_CPU_MIPS",
4046 "TARGET_CPU_SPARC",
4047 "TARGET_CPU_ALPHA",
4048 "TARGET_IPHONE_SIMULATOR",
4049 "TARGET_OS_EMBEDDED",
4050 "TARGET_OS_IPHONE",
4051 "TARGET_OS_MAC",
4052 "TARGET_OS_UNIX",
4053 "TARGET_OS_WIN32",
4054 )
4055 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4056 results = []
4057 for lnum, line in f.ChangedContents():
4058 for match in ifdef_macro.finditer(line):
4059 if match.group(1) in ALWAYS_DEFINED_MACROS:
4060 always_defined = ' %s is always defined. ' % match.group(1)
4061 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4062 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4063 lnum,
4064 always_defined,
4065 did_you_mean))
4066 return results
4067
4068
4069def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4070 """Check all affected files for invalid "if defined" macros."""
4071 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054072 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444073 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054074 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214075 continue
lliabraa35bab3932014-10-01 12:16:444076 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4077 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4078
4079 if not bad_macros:
4080 return []
4081
4082 return [output_api.PresubmitError(
4083 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4084 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4085 bad_macros)]
4086
4087
mlamouria82272622014-09-16 18:45:044088def _CheckForIPCRules(input_api, output_api):
4089 """Check for same IPC rules described in
4090 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4091 """
4092 base_pattern = r'IPC_ENUM_TRAITS\('
4093 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4094 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4095
4096 problems = []
4097 for f in input_api.AffectedSourceFiles(None):
4098 local_path = f.LocalPath()
4099 if not local_path.endswith('.h'):
4100 continue
4101 for line_number, line in f.ChangedContents():
4102 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4103 problems.append(
4104 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4105
4106 if problems:
4107 return [output_api.PresubmitPromptWarning(
4108 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4109 else:
4110 return []
4111
[email protected]b00342e7f2013-03-26 16:21:544112
Stephen Martinis97a394142018-06-07 23:06:054113def _CheckForLongPathnames(input_api, output_api):
4114 """Check to make sure no files being submitted have long paths.
4115 This causes issues on Windows.
4116 """
4117 problems = []
4118 for f in input_api.AffectedSourceFiles(None):
4119 local_path = f.LocalPath()
4120 # Windows has a path limit of 260 characters. Limit path length to 200 so
4121 # that we have some extra for the prefix on dev machines and the bots.
4122 if len(local_path) > 200:
4123 problems.append(local_path)
4124
4125 if problems:
4126 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4127 else:
4128 return []
4129
4130
Daniel Bratell8ba52722018-03-02 16:06:144131def _CheckForIncludeGuards(input_api, output_api):
4132 """Check that header files have proper guards against multiple inclusion.
4133 If a file should not have such guards (and it probably should) then it
4134 should include the string "no-include-guard-because-multiply-included".
4135 """
Daniel Bratell6a75baef62018-06-04 10:04:454136 def is_chromium_header_file(f):
4137 # We only check header files under the control of the Chromium
4138 # project. That is, those outside third_party apart from
4139 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324140 # We also exclude *_message_generator.h headers as they use
4141 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454142 file_with_path = input_api.os_path.normpath(f.LocalPath())
4143 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324144 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454145 (not file_with_path.startswith('third_party') or
4146 file_with_path.startswith(
4147 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144148
4149 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344150 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144151
4152 errors = []
4153
Daniel Bratell6a75baef62018-06-04 10:04:454154 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144155 guard_name = None
4156 guard_line_number = None
4157 seen_guard_end = False
4158
4159 file_with_path = input_api.os_path.normpath(f.LocalPath())
4160 base_file_name = input_api.os_path.splitext(
4161 input_api.os_path.basename(file_with_path))[0]
4162 upper_base_file_name = base_file_name.upper()
4163
4164 expected_guard = replace_special_with_underscore(
4165 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144166
4167 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574168 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4169 # are too many (1000+) files with slight deviations from the
4170 # coding style. The most important part is that the include guard
4171 # is there, and that it's unique, not the name so this check is
4172 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144173 #
4174 # As code becomes more uniform, this could be made stricter.
4175
4176 guard_name_pattern_list = [
4177 # Anything with the right suffix (maybe with an extra _).
4178 r'\w+_H__?',
4179
Daniel Bratell39b5b062018-05-16 18:09:574180 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144181 r'\w+_h',
4182
4183 # Anything including the uppercase name of the file.
4184 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4185 upper_base_file_name)) + r'\w*',
4186 ]
4187 guard_name_pattern = '|'.join(guard_name_pattern_list)
4188 guard_pattern = input_api.re.compile(
4189 r'#ifndef\s+(' + guard_name_pattern + ')')
4190
4191 for line_number, line in enumerate(f.NewContents()):
4192 if 'no-include-guard-because-multiply-included' in line:
4193 guard_name = 'DUMMY' # To not trigger check outside the loop.
4194 break
4195
4196 if guard_name is None:
4197 match = guard_pattern.match(line)
4198 if match:
4199 guard_name = match.group(1)
4200 guard_line_number = line_number
4201
Daniel Bratell39b5b062018-05-16 18:09:574202 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454203 # don't match the chromium style guide, but new files should
4204 # get it right.
4205 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574206 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144207 errors.append(output_api.PresubmitPromptWarning(
4208 'Header using the wrong include guard name %s' % guard_name,
4209 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:574210 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144211 else:
4212 # The line after #ifndef should have a #define of the same name.
4213 if line_number == guard_line_number + 1:
4214 expected_line = '#define %s' % guard_name
4215 if line != expected_line:
4216 errors.append(output_api.PresubmitPromptWarning(
4217 'Missing "%s" for include guard' % expected_line,
4218 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4219 'Expected: %r\nGot: %r' % (expected_line, line)))
4220
4221 if not seen_guard_end and line == '#endif // %s' % guard_name:
4222 seen_guard_end = True
4223 elif seen_guard_end:
4224 if line.strip() != '':
4225 errors.append(output_api.PresubmitPromptWarning(
4226 'Include guard %s not covering the whole file' % (
4227 guard_name), [f.LocalPath()]))
4228 break # Nothing else to check and enough to warn once.
4229
4230 if guard_name is None:
4231 errors.append(output_api.PresubmitPromptWarning(
4232 'Missing include guard %s' % expected_guard,
4233 [f.LocalPath()],
4234 'Missing include guard in %s\n'
4235 'Recommended name: %s\n'
4236 'This check can be disabled by having the string\n'
4237 'no-include-guard-because-multiply-included in the header.' %
4238 (f.LocalPath(), expected_guard)))
4239
4240 return errors
4241
4242
mostynbb639aca52015-01-07 20:31:234243def _CheckForWindowsLineEndings(input_api, output_api):
4244 """Check source code and known ascii text files for Windows style line
4245 endings.
4246 """
earthdok1b5e0ee2015-03-10 15:19:104247 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234248
4249 file_inclusion_pattern = (
4250 known_text_files,
4251 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4252 )
4253
mostynbb639aca52015-01-07 20:31:234254 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534255 source_file_filter = lambda f: input_api.FilterSourceFile(
4256 f, white_list=file_inclusion_pattern, black_list=None)
4257 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504258 include_file = False
4259 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234260 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504261 include_file = True
4262 if include_file:
4263 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234264
4265 if problems:
4266 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4267 'these files to contain Windows style line endings?\n' +
4268 '\n'.join(problems))]
4269
4270 return []
4271
4272
Vaclav Brozekd5de76a2018-03-17 07:57:504273def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134274 """Checks that all source files use SYSLOG properly."""
4275 syslog_files = []
4276 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564277 for line_number, line in f.ChangedContents():
4278 if 'SYSLOG' in line:
4279 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4280
pastarmovj89f7ee12016-09-20 14:58:134281 if syslog_files:
4282 return [output_api.PresubmitPromptWarning(
4283 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4284 ' calls.\nFiles to check:\n', items=syslog_files)]
4285 return []
4286
4287
[email protected]1f7b4172010-01-28 01:17:344288def CheckChangeOnUpload(input_api, output_api):
4289 results = []
4290 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474291 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284292 results.extend(
jam93a6ee792017-02-08 23:59:224293 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194294 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224295 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134296 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164297 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534298 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194299 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274300 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544301 return results
[email protected]ca8d1982009-02-19 16:33:124302
4303
[email protected]1bfb8322014-04-23 01:02:414304def GetTryServerMasterForBot(bot):
4305 """Returns the Try Server master for the given bot.
4306
[email protected]0bb112362014-07-26 04:38:324307 It tries to guess the master from the bot name, but may still fail
4308 and return None. There is no longer a default master.
4309 """
4310 # Potentially ambiguous bot names are listed explicitly.
4311 master_map = {
tandriie5587792016-07-14 00:34:504312 'chromium_presubmit': 'master.tryserver.chromium.linux',
4313 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414314 }
[email protected]0bb112362014-07-26 04:38:324315 master = master_map.get(bot)
4316 if not master:
wnwen4fbaab82016-05-25 12:54:364317 if 'android' in bot:
tandriie5587792016-07-14 00:34:504318 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364319 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504320 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324321 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504322 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324323 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504324 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324325 return master
[email protected]1bfb8322014-04-23 01:02:414326
4327
[email protected]ca8d1982009-02-19 16:33:124328def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544329 results = []
[email protected]1f7b4172010-01-28 01:17:344330 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574331 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544332 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274333 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344334 input_api,
4335 output_api,
[email protected]2fdd1f362013-01-16 03:56:034336 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274337
jam93a6ee792017-02-08 23:59:224338 results.extend(
4339 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544340 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4341 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414342 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4343 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544344 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144345
4346
4347def _CheckTranslationScreenshots(input_api, output_api):
4348 PART_FILE_TAG = "part"
4349 import os
4350 import sys
4351 from io import StringIO
4352
4353 try:
4354 old_sys_path = sys.path
4355 sys.path = sys.path + [input_api.os_path.join(
4356 input_api.PresubmitLocalPath(), 'tools', 'grit')]
4357 import grit.grd_reader
4358 import grit.node.message
4359 import grit.util
4360 finally:
4361 sys.path = old_sys_path
4362
4363 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
4364 """Load the grd file and return a dict of message ids to messages.
4365
4366 Ignores any nested grdp files pointed by <part> tag.
4367 """
4368 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
4369 stop_after=None, first_ids_file=None,
Julian Pastarmov4f7af532019-07-17 19:25:374370 debug=False, defines={'_chromium': 1},
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144371 tags_to_ignore=set([PART_FILE_TAG]))
4372 return {
4373 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
4374 grit.node.message.MessageNode)
4375 }
4376
4377 def _GetGrdpMessagesFromString(grdp_string):
4378 """Parses the contents of a grdp file given in grdp_string.
4379
4380 grd_reader can't parse grdp files directly. Instead, this creates a
4381 temporary directory with a grd file pointing to the grdp file, and loads the
4382 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
4383 """
4384 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
4385 <grit latest_public_release="1" current_release="1">
4386 <release seq="1">
4387 <messages>
4388 <part file="sub.grdp" />
4389 </messages>
4390 </release>
4391 </grit>
4392 """
4393 with grit.util.TempDir({'main.grd': WRAPPER,
4394 'sub.grdp': grdp_string}) as temp_dir:
4395 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
4396
4397 new_or_added_paths = set(f.LocalPath()
4398 for f in input_api.AffectedFiles()
4399 if (f.Action() == 'A' or f.Action() == 'M'))
4400 removed_paths = set(f.LocalPath()
4401 for f in input_api.AffectedFiles(include_deletes=True)
4402 if f.Action() == 'D')
4403
4404 affected_grds = [f for f in input_api.AffectedFiles()
4405 if (f.LocalPath().endswith('.grd') or
4406 f.LocalPath().endswith('.grdp'))]
4407 affected_png_paths = [f.AbsoluteLocalPath()
4408 for f in input_api.AffectedFiles()
4409 if (f.LocalPath().endswith('.png'))]
4410
4411 # Check for screenshots. Developers can upload screenshots using
4412 # tools/translation/upload_screenshots.py which finds and uploads
4413 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4414 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4415 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4416 #
4417 # The logic here is as follows:
4418 #
4419 # - If the CL has a .png file under the screenshots directory for a grd
4420 # file, warn the developer. Actual images should never be checked into the
4421 # Chrome repo.
4422 #
4423 # - If the CL contains modified or new messages in grd files and doesn't
4424 # contain the corresponding .sha1 files, warn the developer to add images
4425 # and upload them via tools/translation/upload_screenshots.py.
4426 #
4427 # - If the CL contains modified or new messages in grd files and the
4428 # corresponding .sha1 files, everything looks good.
4429 #
4430 # - If the CL contains removed messages in grd files but the corresponding
4431 # .sha1 files aren't removed, warn the developer to remove them.
4432 unnecessary_screenshots = []
4433 missing_sha1 = []
4434 unnecessary_sha1_files = []
4435
4436
4437 def _CheckScreenshotAdded(screenshots_dir, message_id):
4438 sha1_path = input_api.os_path.join(
4439 screenshots_dir, message_id + '.png.sha1')
4440 if sha1_path not in new_or_added_paths:
4441 missing_sha1.append(sha1_path)
4442
4443
4444 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4445 sha1_path = input_api.os_path.join(
4446 screenshots_dir, message_id + '.png.sha1')
4447 if sha1_path not in removed_paths:
4448 unnecessary_sha1_files.append(sha1_path)
4449
4450
4451 for f in affected_grds:
4452 file_path = f.LocalPath()
4453 old_id_to_msg_map = {}
4454 new_id_to_msg_map = {}
4455 if file_path.endswith('.grdp'):
4456 if f.OldContents():
4457 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394458 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144459 if f.NewContents():
4460 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394461 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144462 else:
4463 if f.OldContents():
4464 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394465 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144466 if f.NewContents():
4467 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394468 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144469
4470 # Compute added, removed and modified message IDs.
4471 old_ids = set(old_id_to_msg_map)
4472 new_ids = set(new_id_to_msg_map)
4473 added_ids = new_ids - old_ids
4474 removed_ids = old_ids - new_ids
4475 modified_ids = set([])
4476 for key in old_ids.intersection(new_ids):
4477 if (old_id_to_msg_map[key].FormatXml()
4478 != new_id_to_msg_map[key].FormatXml()):
4479 modified_ids.add(key)
4480
4481 grd_name, ext = input_api.os_path.splitext(
4482 input_api.os_path.basename(file_path))
4483 screenshots_dir = input_api.os_path.join(
4484 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4485
4486 # Check the screenshot directory for .png files. Warn if there is any.
4487 for png_path in affected_png_paths:
4488 if png_path.startswith(screenshots_dir):
4489 unnecessary_screenshots.append(png_path)
4490
4491 for added_id in added_ids:
4492 _CheckScreenshotAdded(screenshots_dir, added_id)
4493
4494 for modified_id in modified_ids:
4495 _CheckScreenshotAdded(screenshots_dir, modified_id)
4496
4497 for removed_id in removed_ids:
4498 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4499
4500 results = []
4501 if unnecessary_screenshots:
4502 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394503 'Do not include actual screenshots in the changelist. Run '
4504 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144505 sorted(unnecessary_screenshots)))
4506
4507 if missing_sha1:
4508 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394509 'You are adding or modifying UI strings.\n'
4510 'To ensure the best translations, take screenshots of the relevant UI '
4511 '(https://g.co/chrome/translation) and add these files to your '
4512 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144513
4514 if unnecessary_sha1_files:
4515 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394516 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144517 sorted(unnecessary_sha1_files)))
4518
4519 return results