blob: 37c9a7fd3d5b4ac40d2bf1fde586bda17ba1b1c1 [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$",
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1429 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5431 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0432 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4033)
[email protected]ca8d1982009-02-19 16:33:1234
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Fragment of a regular expression that matches C++ and Objective-C++
37# implementation files.
38_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
39
wnwenbdc444e2016-05-25 13:44:1540
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1941# Fragment of a regular expression that matches C++ and Objective-C++
42# header files.
43_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
44
45
[email protected]06e6d0ff2012-12-11 01:36:4446# Regular expression that matches code only used for test binaries
47# (best effort).
48_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0449 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4450 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4451 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1252 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1853 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4454 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0455 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0556 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0457 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4758 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0459 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0860 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0461 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4162 # EarlGrey app side code for tests.
63 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1764 # Views Examples code
65 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4466)
[email protected]ca8d1982009-02-19 16:33:1267
Daniel Bratell609102be2019-03-27 20:53:2168_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1569
[email protected]eea609a2011-11-18 13:10:1270_TEST_ONLY_WARNING = (
71 'You might be calling functions intended only for testing from\n'
72 'production code. It is OK to ignore this warning if you know what\n'
73 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0774 'not perfect. The commit queue will not block on this warning,\n'
75 'however the android-binary-size trybot will block if the method\n'
76 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1277
78
[email protected]cf9b78f2012-11-14 11:40:2879_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4080 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2181 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
82 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2883
Michael Thiessen44457642020-02-06 00:24:1584# Format: Sequence of tuples containing:
85# * Full import path.
86# * Sequence of strings to show when the pattern matches.
87# * Sequence of path or filename exceptions to this rule
88_BANNED_JAVA_IMPORTS = (
89 (
Colin Blundell170d78c82020-03-12 13:56:0490 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1591 (
92 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
93 ),
94 (
95 'net/android/javatests/src/org/chromium/net/'
96 'AndroidProxySelectorTest.java',
97 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:0498 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:1599 ),
100 ),
101)
wnwenbdc444e2016-05-25 13:44:15102
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.
Eric Stevensona9a980972017-09-23 00:04:41107_BANNED_JAVA_FUNCTIONS = (
108 (
109 'StrictMode.allowThreadDiskReads()',
110 (
111 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
112 'directly.',
113 ),
114 False,
115 ),
116 (
117 'StrictMode.allowThreadDiskWrites()',
118 (
119 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
120 'directly.',
121 ),
122 False,
123 ),
124)
125
Daniel Bratell609102be2019-03-27 20:53:21126# Format: Sequence of tuples containing:
127# * String pattern or, if starting with a slash, a regular expression.
128# * Sequence of strings to show when the pattern matches.
129# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59130_BANNED_OBJC_FUNCTIONS = (
131 (
132 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59135 'prohibited. Please use CrTrackingArea instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 False,
139 ),
140 (
[email protected]eaae1972014-04-16 04:17:26141 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59144 'instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 False,
148 ),
149 (
150 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertPoint:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertPoint:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
167 (
168 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20169 (
170 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59171 'Please use |convertRect:(point) fromView:nil| instead.',
172 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
173 ),
174 True,
175 ),
176 (
177 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20178 (
179 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59180 'Please use |convertRect:(point) toView:nil| instead.',
181 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
182 ),
183 True,
184 ),
185 (
186 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20187 (
188 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59189 'Please use |convertSize:(point) fromView:nil| instead.',
190 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
191 ),
192 True,
193 ),
194 (
195 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20196 (
197 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59198 'Please use |convertSize:(point) toView:nil| instead.',
199 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
200 ),
201 True,
202 ),
jif65398702016-10-27 10:19:48203 (
204 r"/\s+UTF8String\s*]",
205 (
206 'The use of -[NSString UTF8String] is dangerous as it can return null',
207 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
208 'Please use |SysNSStringToUTF8| instead.',
209 ),
210 True,
211 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34212 (
213 r'__unsafe_unretained',
214 (
215 'The use of __unsafe_unretained is almost certainly wrong, unless',
216 'when interacting with NSFastEnumeration or NSInvocation.',
217 'Please use __weak in files build with ARC, nothing otherwise.',
218 ),
219 False,
220 ),
Avi Drissman7382afa02019-04-29 23:27:13221 (
222 'freeWhenDone:NO',
223 (
224 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
225 'Foundation types is prohibited.',
226 ),
227 True,
228 ),
[email protected]127f18ec2012-06-16 05:05:59229)
230
Daniel Bratell609102be2019-03-27 20:53:21231# Format: Sequence of tuples containing:
232# * String pattern or, if starting with a slash, a regular expression.
233# * Sequence of strings to show when the pattern matches.
234# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54235_BANNED_IOS_OBJC_FUNCTIONS = (
236 (
237 r'/\bTEST[(]',
238 (
239 'TEST() macro should not be used in Objective-C++ code as it does not ',
240 'drain the autorelease pool at the end of the test. Use TEST_F() ',
241 'macro instead with a fixture inheriting from PlatformTest (or a ',
242 'typedef).'
243 ),
244 True,
245 ),
246 (
247 r'/\btesting::Test\b',
248 (
249 'testing::Test should not be used in Objective-C++ code as it does ',
250 'not drain the autorelease pool at the end of the test. Use ',
251 'PlatformTest instead.'
252 ),
253 True,
254 ),
255)
256
Peter K. Lee6c03ccff2019-07-15 14:40:05257# Format: Sequence of tuples containing:
258# * String pattern or, if starting with a slash, a regular expression.
259# * Sequence of strings to show when the pattern matches.
260# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
261_BANNED_IOS_EGTEST_FUNCTIONS = (
262 (
263 r'/\bEXPECT_OCMOCK_VERIFY\b',
264 (
265 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
266 'it is meant for GTests. Use [mock verify] instead.'
267 ),
268 True,
269 ),
270)
271
danakj7a2b7082019-05-21 21:13:51272# Directories that contain deprecated Bind() or Callback types.
273# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36274# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51275# echo "-- $i"
danakj710b4c02019-11-28 16:08:45276# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51277# done
278#
279# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
280# when they have been converted to modern callback types (OnceCallback,
281# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
282# checks for them and prevent regressions.
283_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51284 '^apps/',
danakj7a2b7082019-05-21 21:13:51285 '^base/callback.h', # Intentional.
286 '^chrome/app/',
287 '^chrome/browser/',
288 '^chrome/chrome_elf/',
danakj7a2b7082019-05-21 21:13:51289 '^chrome/common/',
290 '^chrome/installer/',
danakj7a2b7082019-05-21 21:13:51291 '^chrome/renderer/',
292 '^chrome/services/',
293 '^chrome/test/',
294 '^chrome/tools/',
295 '^chrome/utility/',
danakj7a2b7082019-05-21 21:13:51296 '^chromecast/media/',
297 '^chromecast/metrics/',
298 '^chromecast/net/',
299 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51300 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51301 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51302 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51303 '^components/arc/',
304 '^components/assist_ranker/',
305 '^components/autofill/',
306 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51307 '^components/browser_watcher/',
danakj7a2b7082019-05-21 21:13:51308 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51309 '^components/chromeos_camera/',
310 '^components/component_updater/',
311 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51312 '^components/cronet/',
313 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51314 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36315 '^components/dom_distiller/',
Joey Scarr164d7072020-04-21 03:13:39316 '^components/download/internal/common/',
danakj7a2b7082019-05-21 21:13:51317 '^components/drive/',
318 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51323 '^components/guest_view/',
324 '^components/heap_profiling/',
325 '^components/history/',
326 '^components/image_fetcher/',
327 '^components/invalidation/',
328 '^components/keyed_service/',
329 '^components/login/',
330 '^components/metrics/',
331 '^components/metrics_services_manager/',
332 '^components/nacl/',
333 '^components/navigation_interception/',
334 '^components/net_log/',
335 '^components/network_time/',
336 '^components/ntp_snippets/',
337 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51338 '^components/offline_pages/',
339 '^components/omnibox/',
340 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51341 '^components/password_manager/',
342 '^components/payments/',
343 '^components/plugins/',
344 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51345 '^components/proxy_config/',
346 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51347 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51348 '^components/rlz/',
349 '^components/safe_browsing/',
350 '^components/search_engines/',
351 '^components/search_provider_logos/',
352 '^components/security_interstitials/',
353 '^components/security_state/',
354 '^components/services/',
355 '^components/sessions/',
356 '^components/signin/',
357 '^components/ssl_errors/',
358 '^components/storage_monitor/',
359 '^components/subresource_filter/',
360 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51361 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51362 '^components/sync_preferences/',
363 '^components/sync_sessions/',
364 '^components/test/',
365 '^components/tracing/',
366 '^components/translate/',
367 '^components/ukm/',
368 '^components/update_client/',
369 '^components/upload_list/',
370 '^components/variations/',
371 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51372 '^components/webcrypto/',
373 '^components/webdata/',
374 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51375 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20376 '^extensions/browser/',
377 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51378 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51379 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51380 '^ios/chrome/',
381 '^ios/components/',
382 '^ios/net/',
383 '^ios/web/',
384 '^ios/web_view/',
385 '^ipc/',
danakj7a2b7082019-05-21 21:13:51386 '^media/base/',
danakjc8576092019-11-26 19:01:36387 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51388 '^media/cast/',
389 '^media/cdm/',
390 '^media/device_monitors/',
danakj7a2b7082019-05-21 21:13:51391 '^media/filters/',
392 '^media/formats/',
393 '^media/gpu/',
394 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51395 '^media/renderers/',
danakj7a2b7082019-05-21 21:13:51396 '^net/',
397 '^ppapi/proxy/',
398 '^ppapi/shared_impl/',
399 '^ppapi/tests/',
400 '^ppapi/thunk/',
401 '^remoting/base/',
402 '^remoting/client/',
danakj7a2b7082019-05-21 21:13:51403 '^remoting/host/',
404 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51405 '^remoting/protocol/',
danakj7a2b7082019-05-21 21:13:51406 '^services/',
danakj7a2b7082019-05-21 21:13:51407 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51408 '^tools/clang/base_bind_rewriters/', # Intentional.
409 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51410))
[email protected]127f18ec2012-06-16 05:05:59411
Daniel Bratell609102be2019-03-27 20:53:21412# Format: Sequence of tuples containing:
413# * String pattern or, if starting with a slash, a regular expression.
414# * Sequence of strings to show when the pattern matches.
415# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
416# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59417_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20418 (
Dave Tapuska98199b612019-07-10 13:30:44419 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53420 (
421 'New code should not use NULL. Use nullptr instead.',
422 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20423 False,
thomasandersone7caaa9b2017-03-29 19:22:53424 (),
425 ),
Peter Kasting94a56c42019-10-25 21:54:04426 (
427 r'/\busing namespace ',
428 (
429 'Using directives ("using namespace x") are banned by the Google Style',
430 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
431 'Explicitly qualify symbols or use using declarations ("using x::foo").',
432 ),
433 True,
434 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
435 ),
Antonio Gomes07300d02019-03-13 20:59:57436 # Make sure that gtest's FRIEND_TEST() macro is not used; the
437 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
438 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53439 (
[email protected]23e6cbc2012-06-16 18:51:20440 'FRIEND_TEST(',
441 (
[email protected]e3c945502012-06-26 20:01:49442 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20443 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
444 ),
445 False,
[email protected]7345da02012-11-27 14:31:49446 (),
[email protected]23e6cbc2012-06-16 18:51:20447 ),
448 (
Dave Tapuska98199b612019-07-10 13:30:44449 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53450 (
451 'Chrome clients wishing to select events on X windows should use',
452 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
453 'you are selecting events from the GPU process, or if you are using',
454 'an XDisplay other than gfx::GetXDisplay().',
455 ),
456 True,
457 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40458 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04459 r"^ui[\\/]gl[\\/].*\.cc$",
460 r"^media[\\/]gpu[\\/].*\.cc$",
461 r"^gpu[\\/].*\.cc$",
Shahbaz Youssefi1b473182020-06-10 18:05:25462 ),
thomasanderson4b569052016-09-14 20:15:53463 ),
464 (
Dave Tapuska98199b612019-07-10 13:30:44465 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20466 (
thomasanderson11aa41d2017-06-08 22:22:38467 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20468 ),
469 True,
470 (
Egor Paskoce145c42018-09-28 19:31:04471 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
472 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
473 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20474 ),
475 ),
476 (
tomhudsone2c14d552016-05-26 17:07:46477 'setMatrixClip',
478 (
479 'Overriding setMatrixClip() is prohibited; ',
480 'the base function is deprecated. ',
481 ),
482 True,
483 (),
484 ),
485 (
[email protected]52657f62013-05-20 05:30:31486 'SkRefPtr',
487 (
488 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22489 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31490 ),
491 True,
492 (),
493 ),
494 (
495 'SkAutoRef',
496 (
497 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
503 (
504 'SkAutoTUnref',
505 (
506 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22507 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31508 ),
509 True,
510 (),
511 ),
512 (
513 'SkAutoUnref',
514 (
515 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
516 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22517 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31518 ),
519 True,
520 (),
521 ),
[email protected]d89eec82013-12-03 14:10:59522 (
523 r'/HANDLE_EINTR\(.*close',
524 (
525 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
526 'descriptor will be closed, and it is incorrect to retry the close.',
527 'Either call close directly and ignore its return value, or wrap close',
528 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
529 ),
530 True,
531 (),
532 ),
533 (
534 r'/IGNORE_EINTR\((?!.*close)',
535 (
536 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
537 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
538 ),
539 True,
540 (
541 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04542 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
543 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59544 ),
545 ),
[email protected]ec5b3f02014-04-04 18:43:43546 (
547 r'/v8::Extension\(',
548 (
549 'Do not introduce new v8::Extensions into the code base, use',
550 'gin::Wrappable instead. See http://crbug.com/334679',
551 ),
552 True,
[email protected]f55c90ee62014-04-12 00:50:03553 (
Egor Paskoce145c42018-09-28 19:31:04554 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03555 ),
[email protected]ec5b3f02014-04-04 18:43:43556 ),
skyostilf9469f72015-04-20 10:38:52557 (
jame2d1a952016-04-02 00:27:10558 '#pragma comment(lib,',
559 (
560 'Specify libraries to link with in build files and not in the source.',
561 ),
562 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41563 (
tzik3f295992018-12-04 20:32:23564 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04565 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41566 ),
jame2d1a952016-04-02 00:27:10567 ),
fdorayc4ac18d2017-05-01 21:39:59568 (
Gabriel Charette7cc6c432018-04-25 20:52:02569 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59570 (
571 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
572 ),
573 False,
574 (),
575 ),
576 (
Gabriel Charette7cc6c432018-04-25 20:52:02577 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59578 (
579 'Consider using THREAD_CHECKER macros instead of the class directly.',
580 ),
581 False,
582 (),
583 ),
dbeamb6f4fde2017-06-15 04:03:06584 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06585 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
586 (
587 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
588 'deprecated (http://crbug.com/634507). Please avoid converting away',
589 'from the Time types in Chromium code, especially if any math is',
590 'being done on time values. For interfacing with platform/library',
591 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
592 'type converter methods instead. For faking TimeXXX values (for unit',
593 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
594 'other use cases, please contact base/time/OWNERS.',
595 ),
596 False,
597 (),
598 ),
599 (
dbeamb6f4fde2017-06-15 04:03:06600 'CallJavascriptFunctionUnsafe',
601 (
602 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
603 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
604 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
605 ),
606 False,
607 (
Egor Paskoce145c42018-09-28 19:31:04608 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
609 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
610 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06611 ),
612 ),
dskiba1474c2bfd62017-07-20 02:19:24613 (
614 'leveldb::DB::Open',
615 (
616 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
617 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
618 "Chrome's tracing, making their memory usage visible.",
619 ),
620 True,
621 (
622 r'^third_party/leveldatabase/.*\.(cc|h)$',
623 ),
Gabriel Charette0592c3a2017-07-26 12:02:04624 ),
625 (
Chris Mumfordc38afb62017-10-09 17:55:08626 'leveldb::NewMemEnv',
627 (
628 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58629 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
630 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08631 ),
632 True,
633 (
634 r'^third_party/leveldatabase/.*\.(cc|h)$',
635 ),
636 ),
637 (
Gabriel Charetted9839bc2017-07-29 14:17:47638 'RunLoop::QuitCurrent',
639 (
Robert Liao64b7ab22017-08-04 23:03:43640 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
641 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47642 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41643 False,
Gabriel Charetted9839bc2017-07-29 14:17:47644 (),
Gabriel Charettea44975052017-08-21 23:14:04645 ),
646 (
647 'base::ScopedMockTimeMessageLoopTaskRunner',
648 (
Gabriel Charette87cc1af2018-04-25 20:52:51649 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11650 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51651 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
652 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
653 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04654 ),
Gabriel Charette87cc1af2018-04-25 20:52:51655 False,
Gabriel Charettea44975052017-08-21 23:14:04656 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57657 ),
658 (
Dave Tapuska98199b612019-07-10 13:30:44659 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57660 (
661 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02662 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57663 ),
664 True,
665 (),
Francois Doray43670e32017-09-27 12:40:38666 ),
667 (
Peter Kasting991618a62019-06-17 22:00:09668 r'/\bstd::stoi\b',
669 (
670 'std::stoi uses exceptions to communicate results. ',
671 'Use base::StringToInt() instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
675 ),
676 (
677 r'/\bstd::stol\b',
678 (
679 'std::stol uses exceptions to communicate results. ',
680 'Use base::StringToInt() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stoul\b',
687 (
688 'std::stoul uses exceptions to communicate results. ',
689 'Use base::StringToUint() instead.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
695 r'/\bstd::stoll\b',
696 (
697 'std::stoll uses exceptions to communicate results. ',
698 'Use base::StringToInt64() instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
702 ),
703 (
704 r'/\bstd::stoull\b',
705 (
706 'std::stoull uses exceptions to communicate results. ',
707 'Use base::StringToUint64() instead.',
708 ),
709 True,
710 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
711 ),
712 (
713 r'/\bstd::stof\b',
714 (
715 'std::stof uses exceptions to communicate results. ',
716 'For locale-independent values, e.g. reading numbers from disk',
717 'profiles, use base::StringToDouble().',
718 'For user-visible values, parse using ICU.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
722 ),
723 (
724 r'/\bstd::stod\b',
725 (
726 'std::stod uses exceptions to communicate results. ',
727 'For locale-independent values, e.g. reading numbers from disk',
728 'profiles, use base::StringToDouble().',
729 'For user-visible values, parse using ICU.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::stold\b',
736 (
737 'std::stold uses exceptions to communicate results. ',
738 'For locale-independent values, e.g. reading numbers from disk',
739 'profiles, use base::StringToDouble().',
740 'For user-visible values, parse using ICU.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
Daniel Bratell69334cc2019-03-26 11:07:45746 r'/\bstd::to_string\b',
747 (
748 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09749 'For locale-independent strings, e.g. writing numbers to disk',
750 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45751 'For user-visible strings, use base::FormatNumber() and',
752 'the related functions in base/i18n/number_formatting.h.',
753 ),
Peter Kasting991618a62019-06-17 22:00:09754 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21755 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45756 ),
757 (
758 r'/\bstd::shared_ptr\b',
759 (
760 'std::shared_ptr should not be used. Use scoped_refptr instead.',
761 ),
762 True,
Andreas Haas63f58792019-11-07 10:56:44763 [_THIRD_PARTY_EXCEPT_BLINK,
764 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
765 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21766 ),
767 (
Peter Kasting991618a62019-06-17 22:00:09768 r'/\bstd::weak_ptr\b',
769 (
770 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
Daniel Bratell609102be2019-03-27 20:53:21776 r'/\blong long\b',
777 (
778 'long long is banned. Use stdint.h if you need a 64 bit number.',
779 ),
780 False, # Only a warning since it is already used.
781 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
782 ),
783 (
784 r'/\bstd::bind\b',
785 (
786 'std::bind is banned because of lifetime risks.',
787 'Use base::BindOnce or base::BindRepeating instead.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\b#include <chrono>\b',
794 (
795 '<chrono> overlaps with Time APIs in base. Keep using',
796 'base classes.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
800 ),
801 (
802 r'/\b#include <exception>\b',
803 (
804 'Exceptions are banned and disabled in Chromium.',
805 ),
806 True,
807 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
808 ),
809 (
810 r'/\bstd::function\b',
811 (
812 'std::function is banned. Instead use base::Callback which directly',
813 'supports Chromium\'s weak pointers, ref counting and more.',
814 ),
Peter Kasting991618a62019-06-17 22:00:09815 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21816 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
817 ),
818 (
819 r'/\b#include <random>\b',
820 (
821 'Do not use any random number engines from <random>. Instead',
822 'use base::RandomBitGenerator.',
823 ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
826 ),
827 (
828 r'/\bstd::ratio\b',
829 (
830 'std::ratio is banned by the Google Style Guide.',
831 ),
832 True,
833 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45834 ),
835 (
Francois Doray43670e32017-09-27 12:40:38836 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
837 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
838 (
839 'Use the new API in base/threading/thread_restrictions.h.',
840 ),
Gabriel Charette04b138f2018-08-06 00:03:22841 False,
Francois Doray43670e32017-09-27 12:40:38842 (),
843 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38844 (
danakj7a2b7082019-05-21 21:13:51845 r'/\bbase::Bind\(',
846 (
847 'Please use base::Bind{Once,Repeating} instead',
848 'of base::Bind. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Callback[<:]',
855 (
856 'Please use base::{Once,Repeating}Callback instead',
857 'of base::Callback. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
863 r'/\bbase::Closure\b',
864 (
865 'Please use base::{Once,Repeating}Closure instead',
866 'of base::Closure. (crbug.com/714018)',
867 ),
868 False,
Erik Staaba737d7602019-11-25 18:41:07869 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51870 ),
871 (
Michael Giuffrida7f93d6922019-04-19 14:39:58872 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 'RunMessageLoop is deprecated, use RunLoop instead.',
875 ),
876 False,
877 (),
878 ),
879 (
Dave Tapuska98199b612019-07-10 13:30:44880 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19881 (
882 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
891 "if you're convinced you need this.",
892 ),
893 False,
894 (),
895 ),
896 (
Dave Tapuska98199b612019-07-10 13:30:44897 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19898 (
899 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04900 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19901 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
902 'async events instead of flushing threads.',
903 ),
904 False,
905 (),
906 ),
907 (
908 r'MessageLoopRunner',
909 (
910 'MessageLoopRunner is deprecated, use RunLoop instead.',
911 ),
912 False,
913 (),
914 ),
915 (
Dave Tapuska98199b612019-07-10 13:30:44916 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19917 (
918 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
919 "gab@ if you found a use case where this is the only solution.",
920 ),
921 False,
922 (),
923 ),
924 (
Victor Costane48a2e82019-03-15 22:02:34925 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16926 (
Victor Costane48a2e82019-03-15 22:02:34927 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16928 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
929 ),
930 True,
931 (
932 r'^sql/initialization\.(cc|h)$',
933 r'^third_party/sqlite/.*\.(c|cc|h)$',
934 ),
935 ),
Matt Menke7f520a82018-03-28 21:38:37936 (
Dave Tapuska98199b612019-07-10 13:30:44937 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47938 (
939 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
940 'base::RandomShuffle instead.'
941 ),
942 True,
943 (),
944 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24945 (
946 'ios/web/public/test/http_server',
947 (
948 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
949 ),
950 False,
951 (),
952 ),
Robert Liao764c9492019-01-24 18:46:28953 (
954 'GetAddressOf',
955 (
956 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Robert Liaoe794041e2019-10-03 17:16:46957 'implicated in a few leaks. Use operator& instead. See ',
958 'http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28959 ),
960 True,
961 (),
962 ),
Antonio Gomes07300d02019-03-13 20:59:57963 (
964 'DEFINE_TYPE_CASTS',
965 (
966 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
967 '//third_party/blink/renderer/platform/casting.h.'
968 ),
969 True,
970 (
971 r'^third_party/blink/renderer/.*\.(cc|h)$',
972 ),
973 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38974 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45975 r'/\bIsHTML.+Element\(\b',
976 (
977 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
978 ' helpers IsA<HTMLXXXXElement> from ',
979 '//third_party/blink/renderer/platform/casting.h.'
980 ),
981 False,
982 (
983 r'^third_party/blink/renderer/.*\.(cc|h)$',
984 ),
985 ),
986 (
987 r'/\bToHTML.+Element(|OrNull)\(\b',
988 (
989 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
990 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
991 'and DynamicTo<HTMLXXXXElement> from ',
992 '//third_party/blink/renderer/platform/casting.h.'
993 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
994 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
995 ),
996 False,
997 (
998 r'^third_party/blink/renderer/.*\.(cc|h)$',
999 ),
1000 ),
1001 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371002 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381003 (
1004 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1005 ),
1006 True,
1007 (),
1008 ),
Ben Lewisa9514602019-04-29 17:53:051009 (
1010 'SHFileOperation',
1011 (
1012 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1013 'complex functions to achieve the same goals. Use IFileOperation for ',
1014 'any esoteric actions instead.'
1015 ),
1016 True,
1017 (),
1018 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181019 (
Cliff Smolinsky81951642019-04-30 21:39:511020 'StringFromGUID2',
1021 (
1022 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1023 'Use base::win::String16FromGUID instead.'
1024 ),
1025 True,
1026 (
1027 r'/base/win/win_util_unittest.cc'
1028 ),
1029 ),
1030 (
1031 'StringFromCLSID',
1032 (
1033 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1034 'Use base::win::String16FromGUID instead.'
1035 ),
1036 True,
1037 (
1038 r'/base/win/win_util_unittest.cc'
1039 ),
1040 ),
1041 (
Avi Drissman7382afa02019-04-29 23:27:131042 'kCFAllocatorNull',
1043 (
1044 'The use of kCFAllocatorNull with the NoCopy creation of ',
1045 'CoreFoundation types is prohibited.',
1046 ),
1047 True,
1048 (),
1049 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291050 (
1051 'mojo::ConvertTo',
1052 (
1053 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1054 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1055 'StringTraits if you would like to convert between custom types and',
1056 'the wire format of mojom types.'
1057 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221058 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291059 (
Wezf89dec092019-09-11 19:38:331060 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1061 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291062 r'^third_party/blink/.*\.(cc|h)$',
1063 r'^content/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Robert Liao1d78df52019-11-11 20:02:011066 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161067 'GetInterfaceProvider',
1068 (
1069 'InterfaceProvider is deprecated.',
1070 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1071 'or Platform::GetBrowserInterfaceBroker.'
1072 ),
1073 False,
1074 (),
1075 ),
1076 (
Robert Liao1d78df52019-11-11 20:02:011077 'CComPtr',
1078 (
1079 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1080 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1081 'details.'
1082 ),
1083 False,
1084 (),
1085 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201086 (
1087 r'/\b(IFACE|STD)METHOD_?\(',
1088 (
1089 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1090 'Instead, always use IFACEMETHODIMP in the declaration.'
1091 ),
1092 False,
1093 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1094 ),
Allen Bauer53b43fb12020-03-12 17:21:471095 (
1096 'set_owned_by_client',
1097 (
1098 'set_owned_by_client is deprecated.',
1099 'views::View already owns the child views by default. This introduces ',
1100 'a competing ownership model which makes the code difficult to reason ',
1101 'about. See http://crbug.com/1044687 for more details.'
1102 ),
1103 False,
1104 (),
1105 ),
Eric Secklerbe6f48d2020-05-06 18:09:121106 (
1107 r'/\bTRACE_EVENT_ASYNC_',
1108 (
1109 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1110 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1111 ),
1112 False,
1113 (
1114 r'^base/trace_event/.*',
1115 r'^base/tracing/.*',
1116 ),
1117 ),
[email protected]127f18ec2012-06-16 05:05:591118)
1119
Mario Sanchez Prada2472cab2019-09-18 10:58:311120# Format: Sequence of tuples containing:
1121# * String pattern or, if starting with a slash, a regular expression.
1122# * Sequence of strings to show when the pattern matches.
1123_DEPRECATED_MOJO_TYPES = (
1124 (
1125 r'/\bmojo::AssociatedBinding\b',
1126 (
1127 'mojo::AssociatedBinding<Interface> is deprecated.',
1128 'Use mojo::AssociatedReceiver<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::AssociatedBindingSet\b',
1133 (
1134 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1135 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::AssociatedInterfacePtr\b',
1140 (
1141 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1142 'Use mojo::AssociatedRemote<Interface> instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1147 (
1148 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1149 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1150 ),
1151 ),
1152 (
1153 r'/\bmojo::AssociatedInterfaceRequest\b',
1154 (
1155 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1156 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1157 ),
1158 ),
1159 (
1160 r'/\bmojo::Binding\b',
1161 (
1162 'mojo::Binding<Interface> is deprecated.',
1163 'Use mojo::Receiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::BindingSet\b',
1168 (
1169 'mojo::BindingSet<Interface> is deprecated.',
1170 'Use mojo::ReceiverSet<Interface> instead.',
1171 ),
1172 ),
1173 (
1174 r'/\bmojo::InterfacePtr\b',
1175 (
1176 'mojo::InterfacePtr<Interface> is deprecated.',
1177 'Use mojo::Remote<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::InterfacePtrInfo\b',
1182 (
1183 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1184 'Use mojo::PendingRemote<Interface> instead.',
1185 ),
1186 ),
1187 (
1188 r'/\bmojo::InterfaceRequest\b',
1189 (
1190 'mojo::InterfaceRequest<Interface> is deprecated.',
1191 'Use mojo::PendingReceiver<Interface> instead.',
1192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeRequest\b',
1196 (
1197 'mojo::MakeRequest is deprecated.',
1198 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1203 (
1204 'mojo::MakeRequest is deprecated.',
1205 'Use mojo::AssociatedRemote::'
1206 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongBinding\b',
1211 (
1212 'mojo::MakeStrongBinding is deprecated.',
1213 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1214 'mojo::MakeSelfOwnedReceiver() instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::MakeStrongAssociatedBinding\b',
1219 (
1220 'mojo::MakeStrongAssociatedBinding is deprecated.',
1221 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1222 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1223 ),
1224 ),
1225 (
1226 r'/\bmojo::StrongAssociatedBindingSet\b',
1227 (
1228 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1229 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1230 ),
1231 ),
1232 (
1233 r'/\bmojo::StrongBindingSet\b',
1234 (
1235 'mojo::StrongBindingSet<Interface> is deprecated.',
1236 'Use mojo::UniqueReceiverSet<Interface> instead.',
1237 ),
1238 ),
1239)
wnwenbdc444e2016-05-25 13:44:151240
mlamouria82272622014-09-16 18:45:041241_IPC_ENUM_TRAITS_DEPRECATED = (
1242 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501243 'See http://www.chromium.org/Home/chromium-security/education/'
1244 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041245
Stephen Martinis97a394142018-06-07 23:06:051246_LONG_PATH_ERROR = (
1247 'Some files included in this CL have file names that are too long (> 200'
1248 ' characters). If committed, these files will cause issues on Windows. See'
1249 ' https://crbug.com/612667 for more details.'
1250)
1251
Shenghua Zhangbfaa38b82017-11-16 21:58:021252_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041253 r".*[\\/]BuildHooksAndroidImpl\.java",
1254 r".*[\\/]LicenseContentProvider\.java",
1255 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281256 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021257]
[email protected]127f18ec2012-06-16 05:05:591258
Mohamed Heikald048240a2019-11-12 16:57:371259# List of image extensions that are used as resources in chromium.
1260_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1261
Sean Kau46e29bc2017-08-28 16:31:161262# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401263_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041264 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401265 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041266 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1267 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041268 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431269 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161270]
1271
1272
[email protected]b00342e7f2013-03-26 16:21:541273_VALID_OS_MACROS = (
1274 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081275 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541276 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121277 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_BSD',
1279 'OS_CAT', # For testing.
1280 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041281 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371283 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_IOS',
1285 'OS_LINUX',
1286 'OS_MACOSX',
1287 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211288 'OS_NACL_NONSFI',
1289 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121290 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_OPENBSD',
1292 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371293 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_WIN',
1296)
1297
1298
Andrew Grieveb773bad2020-06-05 18:00:381299# These are not checked on the public chromium-presubmit trybot.
1300# Add files here that rely on .py files that exists only for target_os="android"
1301# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401302_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391303 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381304 'build/android/devil_chromium.pydeps',
1305 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1306 'build/android/gyp/jinja_template.pydeps',
1307 'build/android/resource_sizes.pydeps',
1308 'build/android/test_runner.pydeps',
1309 'build/android/test_wrapper/logdog_wrapper.pydeps',
1310 'chrome/android/features/create_stripped_java_factory.pydeps',
1311 'testing/scripts/run_android_wpt.pydeps',
1312 'third_party/android_platform/development/scripts/stack.pydeps',
1313]
1314
1315
1316_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'base/android/jni_generator/jni_generator.pydeps',
1318 'base/android/jni_generator/jni_registration_generator.pydeps',
1319 'build/android/gyp/aar.pydeps',
1320 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271321 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381323 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111329 'build/android/gyp/create_app_bundle_apks.pydeps',
1330 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361331 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221332 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591334 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421336 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/filter_zip.pydeps',
1339 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361340 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581342 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261344 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011345 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/lint.pydeps',
1347 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/merge_manifest.pydeps',
1349 'build/android/gyp/prepare_resources.pydeps',
1350 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461351 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241352 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461354 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561355 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/incremental_install/generate_android_manifest.pydeps',
1357 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271359 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1360 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381361 'components/module_installer/android/module_desc_java.pydeps',
1362 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421363 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1364 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131365 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191366 ('third_party/blink/renderer/bindings/scripts/'
1367 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061368 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221369 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401370]
1371
wnwenbdc444e2016-05-25 13:44:151372
agrievef32bcc72016-04-04 14:57:401373_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1374
1375
Eric Boren6fd2b932018-01-25 15:05:081376# Bypass the AUTHORS check for these accounts.
1377_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591378 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451379 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591380 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521381 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1382 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041383 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271384 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041385 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301386 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081387
1388
Daniel Bratell65b033262019-04-23 08:17:061389def _IsCPlusPlusFile(input_api, file_path):
1390 """Returns True if this file contains C++-like code (and not Python,
1391 Go, Java, MarkDown, ...)"""
1392
1393 ext = input_api.os_path.splitext(file_path)[1]
1394 # This list is compatible with CppChecker.IsCppFile but we should
1395 # consider adding ".c" to it. If we do that we can use this function
1396 # at more places in the code.
1397 return ext in (
1398 '.h',
1399 '.cc',
1400 '.cpp',
1401 '.m',
1402 '.mm',
1403 )
1404
1405def _IsCPlusPlusHeaderFile(input_api, file_path):
1406 return input_api.os_path.splitext(file_path)[1] == ".h"
1407
1408
1409def _IsJavaFile(input_api, file_path):
1410 return input_api.os_path.splitext(file_path)[1] == ".java"
1411
1412
1413def _IsProtoFile(input_api, file_path):
1414 return input_api.os_path.splitext(file_path)[1] == ".proto"
1415
[email protected]55459852011-08-10 15:17:191416def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1417 """Attempts to prevent use of functions intended only for testing in
1418 non-testing code. For now this is just a best-effort implementation
1419 that ignores header files and may have some false positives. A
1420 better implementation would probably need a proper C++ parser.
1421 """
1422 # We only scan .cc files and the like, as the declaration of
1423 # for-testing functions in header files are hard to distinguish from
1424 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491425 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191426
jochenc0d4808c2015-07-27 09:25:421427 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191428 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091429 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191430 exclusion_pattern = input_api.re.compile(
1431 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1432 base_function_pattern, base_function_pattern))
1433
1434 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441435 black_list = (_EXCLUDED_PATHS +
1436 _TEST_CODE_EXCLUDED_PATHS +
1437 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191438 return input_api.FilterSourceFile(
1439 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491440 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191441 black_list=black_list)
1442
1443 problems = []
1444 for f in input_api.AffectedSourceFiles(FilterFile):
1445 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241446 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031447 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461448 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031449 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191450 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031451 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191452
1453 if problems:
[email protected]f7051d52013-04-02 18:31:421454 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031455 else:
1456 return []
[email protected]55459852011-08-10 15:17:191457
1458
Vaclav Brozek7dbc28c2018-03-27 08:35:231459def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1460 """This is a simplified version of
1461 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1462 """
1463 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1464 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1465 name_pattern = r'ForTest(s|ing)?'
1466 # Describes an occurrence of "ForTest*" inside a // comment.
1467 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1468 # Catch calls.
1469 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1470 # Ignore definitions. (Comments are ignored separately.)
1471 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1472
1473 problems = []
1474 sources = lambda x: input_api.FilterSourceFile(
1475 x,
1476 black_list=(('(?i).*test', r'.*\/junit\/')
1477 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491478 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231479 )
1480 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1481 local_path = f.LocalPath()
1482 is_inside_javadoc = False
1483 for line_number, line in f.ChangedContents():
1484 if is_inside_javadoc and javadoc_end_re.search(line):
1485 is_inside_javadoc = False
1486 if not is_inside_javadoc and javadoc_start_re.search(line):
1487 is_inside_javadoc = True
1488 if is_inside_javadoc:
1489 continue
1490 if (inclusion_re.search(line) and
1491 not comment_re.search(line) and
1492 not exclusion_re.search(line)):
1493 problems.append(
1494 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1495
1496 if problems:
1497 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1498 else:
1499 return []
1500
1501
[email protected]10689ca2011-09-02 02:31:541502def _CheckNoIOStreamInHeaders(input_api, output_api):
1503 """Checks to make sure no .h files include <iostream>."""
1504 files = []
1505 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1506 input_api.re.MULTILINE)
1507 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1508 if not f.LocalPath().endswith('.h'):
1509 continue
1510 contents = input_api.ReadFile(f)
1511 if pattern.search(contents):
1512 files.append(f)
1513
1514 if len(files):
yolandyandaabc6d2016-04-18 18:29:391515 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061516 'Do not #include <iostream> in header files, since it inserts static '
1517 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541518 '#include <ostream>. See http://crbug.com/94794',
1519 files) ]
1520 return []
1521
Danil Chapovalov3518f362018-08-11 16:13:431522def _CheckNoStrCatRedefines(input_api, output_api):
1523 """Checks no windows headers with StrCat redefined are included directly."""
1524 files = []
1525 pattern_deny = input_api.re.compile(
1526 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1527 input_api.re.MULTILINE)
1528 pattern_allow = input_api.re.compile(
1529 r'^#include\s"base/win/windows_defines.inc"',
1530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 contents = input_api.ReadFile(f)
1533 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1534 files.append(f.LocalPath())
1535
1536 if len(files):
1537 return [output_api.PresubmitError(
1538 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1539 'directly since they pollute code with StrCat macro. Instead, '
1540 'include matching header from base/win. See http://crbug.com/856536',
1541 files) ]
1542 return []
1543
[email protected]10689ca2011-09-02 02:31:541544
[email protected]72df4e782012-06-21 16:28:181545def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521546 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181547 problems = []
1548 for f in input_api.AffectedFiles():
1549 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1550 continue
1551
1552 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041553 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181554 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1555
1556 if not problems:
1557 return []
1558 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1559 '\n'.join(problems))]
1560
Dominic Battre033531052018-09-24 15:45:341561def _CheckNoDISABLETypoInTests(input_api, output_api):
1562 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1563
1564 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1565 instead of DISABLED_. To filter false positives, reports are only generated
1566 if a corresponding MAYBE_ line exists.
1567 """
1568 problems = []
1569
1570 # The following two patterns are looked for in tandem - is a test labeled
1571 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1572 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1573 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1574
1575 # This is for the case that a test is disabled on all platforms.
1576 full_disable_pattern = input_api.re.compile(
1577 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1578 input_api.re.MULTILINE)
1579
Katie Df13948e2018-09-25 07:33:441580 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341581 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1582 continue
1583
1584 # Search for MABYE_, DISABLE_ pairs.
1585 disable_lines = {} # Maps of test name to line number.
1586 maybe_lines = {}
1587 for line_num, line in f.ChangedContents():
1588 disable_match = disable_pattern.search(line)
1589 if disable_match:
1590 disable_lines[disable_match.group(1)] = line_num
1591 maybe_match = maybe_pattern.search(line)
1592 if maybe_match:
1593 maybe_lines[maybe_match.group(1)] = line_num
1594
1595 # Search for DISABLE_ occurrences within a TEST() macro.
1596 disable_tests = set(disable_lines.keys())
1597 maybe_tests = set(maybe_lines.keys())
1598 for test in disable_tests.intersection(maybe_tests):
1599 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1600
1601 contents = input_api.ReadFile(f)
1602 full_disable_match = full_disable_pattern.search(contents)
1603 if full_disable_match:
1604 problems.append(' %s' % f.LocalPath())
1605
1606 if not problems:
1607 return []
1608 return [
1609 output_api.PresubmitPromptWarning(
1610 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1611 '\n'.join(problems))
1612 ]
1613
[email protected]72df4e782012-06-21 16:28:181614
danakj61c1aa22015-10-26 19:55:521615def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571616 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521617 errors = []
1618 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1619 input_api.re.MULTILINE)
1620 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1621 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1622 continue
1623 for lnum, line in f.ChangedContents():
1624 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171625 errors.append(output_api.PresubmitError(
1626 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571627 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171628 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521629 return errors
1630
1631
Makoto Shimazu3ad422cd2019-05-08 02:35:141632def _FindHistogramNameInChunk(histogram_name, chunk):
1633 """Tries to find a histogram name or prefix in a line.
1634
1635 Returns the existence of the histogram name, or None if it needs more chunk
1636 to determine."""
mcasasb7440c282015-02-04 14:52:191637 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1638 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141639 if '<affected-histogram' in chunk:
1640 # If the tag is not completed, needs more chunk to get the name.
1641 if not '>' in chunk:
1642 return None
1643 if not 'name="' in chunk:
1644 return False
1645 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1646 # expect the only attribute is the name.
1647 histogram_prefix = chunk.split('"')[1]
1648 return histogram_prefix in histogram_name
1649 # Typically the whole histogram name should in the line.
1650 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191651
1652
1653def _CheckUmaHistogramChanges(input_api, output_api):
1654 """Check that UMA histogram names in touched lines can still be found in other
1655 lines of the patch or in histograms.xml. Note that this check would not catch
1656 the reverse: changes in histograms.xml not matched in the code itself."""
1657 touched_histograms = []
1658 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471659 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1660 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1661 name_pattern = r'"(.*?)"'
1662 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1663 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1664 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1665 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1666 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171667 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191668 for f in input_api.AffectedFiles():
1669 # If histograms.xml itself is modified, keep the modified lines for later.
1670 if f.LocalPath().endswith(('histograms.xml')):
1671 histograms_xml_modifications = f.ChangedContents()
1672 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471673 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1674 single_line_re = single_line_c_re
1675 split_line_prefix_re = split_line_c_prefix_re
1676 elif f.LocalPath().endswith(('java')):
1677 single_line_re = single_line_java_re
1678 split_line_prefix_re = split_line_java_prefix_re
1679 else:
mcasasb7440c282015-02-04 14:52:191680 continue
1681 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171682 if last_line_matched_prefix:
1683 suffix_found = split_line_suffix_re.search(line)
1684 if suffix_found :
1685 touched_histograms.append([suffix_found.group(1), f, line_num])
1686 last_line_matched_prefix = False
1687 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061688 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191689 if found:
1690 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171691 continue
1692 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191693
1694 # Search for the touched histogram names in the local modifications to
1695 # histograms.xml, and, if not found, on the base histograms.xml file.
1696 unmatched_histograms = []
1697 for histogram_info in touched_histograms:
1698 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141699 chunk = ''
mcasasb7440c282015-02-04 14:52:191700 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141701 chunk += line
1702 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1703 if histogram_name_found is None:
1704 continue
1705 chunk = ''
mcasasb7440c282015-02-04 14:52:191706 if histogram_name_found:
1707 break
1708 if not histogram_name_found:
1709 unmatched_histograms.append(histogram_info)
1710
eromanb90c82e7e32015-04-01 15:13:491711 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191712 problems = []
1713 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491714 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191715 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451716 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191717 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141718 chunk = ''
mcasasb7440c282015-02-04 14:52:191719 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141720 chunk += line
1721 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1722 chunk)
1723 if histogram_name_found is None:
1724 continue
1725 chunk = ''
mcasasb7440c282015-02-04 14:52:191726 if histogram_name_found:
1727 break
1728 if not histogram_name_found:
1729 problems.append(' [%s:%d] %s' %
1730 (f.LocalPath(), line_num, histogram_name))
1731
1732 if not problems:
1733 return []
1734 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1735 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491736 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191737
wnwenbdc444e2016-05-25 13:44:151738
yolandyandaabc6d2016-04-18 18:29:391739def _CheckFlakyTestUsage(input_api, output_api):
1740 """Check that FlakyTest annotation is our own instead of the android one"""
1741 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1742 files = []
1743 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1744 if f.LocalPath().endswith('Test.java'):
1745 if pattern.search(input_api.ReadFile(f)):
1746 files.append(f)
1747 if len(files):
1748 return [output_api.PresubmitError(
1749 'Use org.chromium.base.test.util.FlakyTest instead of '
1750 'android.test.FlakyTest',
1751 files)]
1752 return []
mcasasb7440c282015-02-04 14:52:191753
wnwenbdc444e2016-05-25 13:44:151754
[email protected]8ea5d4b2011-09-13 21:49:221755def _CheckNoNewWStrings(input_api, output_api):
1756 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271757 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221758 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201759 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571760 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341761 '/win/' in f.LocalPath() or
1762 'chrome_elf' in f.LocalPath() or
1763 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201764 continue
[email protected]8ea5d4b2011-09-13 21:49:221765
[email protected]a11dbe9b2012-08-07 01:32:581766 allowWString = False
[email protected]b5c24292011-11-28 14:38:201767 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581768 if 'presubmit: allow wstring' in line:
1769 allowWString = True
1770 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271771 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581772 allowWString = False
1773 else:
1774 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221775
[email protected]55463aa62011-10-12 00:48:271776 if not problems:
1777 return []
1778 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581779 ' If you are calling a cross-platform API that accepts a wstring, '
1780 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271781 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221782
1783
[email protected]2a8ac9c2011-10-19 17:20:441784def _CheckNoDEPSGIT(input_api, output_api):
1785 """Make sure .DEPS.git is never modified manually."""
1786 if any(f.LocalPath().endswith('.DEPS.git') for f in
1787 input_api.AffectedFiles()):
1788 return [output_api.PresubmitError(
1789 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1790 'automated system based on what\'s in DEPS and your changes will be\n'
1791 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501792 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1793 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441794 'for more information')]
1795 return []
1796
1797
tandriief664692014-09-23 14:51:471798def _CheckValidHostsInDEPS(input_api, output_api):
1799 """Checks that DEPS file deps are from allowed_hosts."""
1800 # Run only if DEPS file has been modified to annoy fewer bystanders.
1801 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1802 return []
1803 # Outsource work to gclient verify
1804 try:
John Budorickf20c0042019-04-25 23:23:401805 gclient_path = input_api.os_path.join(
1806 input_api.PresubmitLocalPath(),
1807 'third_party', 'depot_tools', 'gclient.py')
1808 input_api.subprocess.check_output(
1809 [input_api.python_executable, gclient_path, 'verify'],
1810 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471811 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201812 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471813 return [output_api.PresubmitError(
1814 'DEPS file must have only git dependencies.',
1815 long_text=error.output)]
1816
1817
Mario Sanchez Prada2472cab2019-09-18 10:58:311818def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1819 type_name, message):
1820 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1821
1822 Returns an string composed of the name of the file, the line number where the
1823 match has been found and the additional text passed as |message| in case the
1824 target type name matches the text inside the line passed as parameter.
1825 """
Peng Huang9c5949a02020-06-11 19:20:541826 result = []
1827
1828 if line.endswith(" nocheck"):
1829 return result
1830
Mario Sanchez Prada2472cab2019-09-18 10:58:311831 matched = False
1832 if type_name[0:1] == '/':
1833 regex = type_name[1:]
1834 if input_api.re.search(regex, line):
1835 matched = True
1836 elif type_name in line:
1837 matched = True
1838
Mario Sanchez Prada2472cab2019-09-18 10:58:311839 if matched:
1840 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1841 for message_line in message:
1842 result.append(' %s' % message_line)
1843
1844 return result
1845
1846
[email protected]127f18ec2012-06-16 05:05:591847def _CheckNoBannedFunctions(input_api, output_api):
1848 """Make sure that banned functions are not used."""
1849 warnings = []
1850 errors = []
1851
wnwenbdc444e2016-05-25 13:44:151852 def IsBlacklisted(affected_file, blacklist):
1853 local_path = affected_file.LocalPath()
1854 for item in blacklist:
1855 if input_api.re.match(item, local_path):
1856 return True
1857 return False
1858
Peter K. Lee6c03ccff2019-07-15 14:40:051859 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541860 local_path = affected_file.LocalPath()
1861 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1862 return False
1863 basename = input_api.os_path.basename(local_path)
1864 if 'ios' in basename.split('_'):
1865 return True
1866 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1867 if sep and 'ios' in local_path.split(sep):
1868 return True
1869 return False
1870
wnwenbdc444e2016-05-25 13:44:151871 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311872 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1873 func_name, message)
1874 if problems:
wnwenbdc444e2016-05-25 13:44:151875 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311876 errors.extend(problems)
1877 else:
1878 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151879
Eric Stevensona9a980972017-09-23 00:04:411880 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1881 for f in input_api.AffectedFiles(file_filter=file_filter):
1882 for line_num, line in f.ChangedContents():
1883 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1884 CheckForMatch(f, line_num, line, func_name, message, error)
1885
[email protected]127f18ec2012-06-16 05:05:591886 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1887 for f in input_api.AffectedFiles(file_filter=file_filter):
1888 for line_num, line in f.ChangedContents():
1889 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151890 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591891
Peter K. Lee6c03ccff2019-07-15 14:40:051892 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541893 for line_num, line in f.ChangedContents():
1894 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1895 CheckForMatch(f, line_num, line, func_name, message, error)
1896
Peter K. Lee6c03ccff2019-07-15 14:40:051897 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1898 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1899 for line_num, line in f.ChangedContents():
1900 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1901 CheckForMatch(f, line_num, line, func_name, message, error)
1902
[email protected]127f18ec2012-06-16 05:05:591903 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1904 for f in input_api.AffectedFiles(file_filter=file_filter):
1905 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491906 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491907 if IsBlacklisted(f, excluded_paths):
1908 continue
wnwenbdc444e2016-05-25 13:44:151909 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591910
1911 result = []
1912 if (warnings):
1913 result.append(output_api.PresubmitPromptWarning(
1914 'Banned functions were used.\n' + '\n'.join(warnings)))
1915 if (errors):
1916 result.append(output_api.PresubmitError(
1917 'Banned functions were used.\n' + '\n'.join(errors)))
1918 return result
1919
1920
Michael Thiessen44457642020-02-06 00:24:151921def _CheckAndroidNoBannedImports(input_api, output_api):
1922 """Make sure that banned java imports are not used."""
1923 errors = []
1924
1925 def IsException(path, exceptions):
1926 for exception in exceptions:
1927 if (path.startswith(exception)):
1928 return True
1929 return False
1930
1931 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1932 for f in input_api.AffectedFiles(file_filter=file_filter):
1933 for line_num, line in f.ChangedContents():
1934 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1935 if IsException(f.LocalPath(), exceptions):
1936 continue;
1937 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1938 'import ' + import_name, message)
1939 if problems:
1940 errors.extend(problems)
1941 result = []
1942 if (errors):
1943 result.append(output_api.PresubmitError(
1944 'Banned imports were used.\n' + '\n'.join(errors)))
1945 return result
1946
1947
Mario Sanchez Prada2472cab2019-09-18 10:58:311948def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1949 """Make sure that old Mojo types are not used."""
1950 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571951 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311952
Mario Sanchez Pradaaab91382019-12-19 08:57:091953 # For any path that is not an "ok" or an "error" path, a warning will be
1954 # raised if deprecated mojo types are found.
1955 ok_paths = ['components/arc']
1956 error_paths = ['third_party/blink', 'content']
1957
Mario Sanchez Prada2472cab2019-09-18 10:58:311958 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1959 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571960 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091961 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311962 continue
1963
1964 for line_num, line in f.ChangedContents():
1965 for func_name, message in _DEPRECATED_MOJO_TYPES:
1966 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1967 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571968
Mario Sanchez Prada2472cab2019-09-18 10:58:311969 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091970 # Raise errors inside |error_paths| and warnings everywhere else.
1971 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571972 errors.extend(problems)
1973 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311974 warnings.extend(problems)
1975
1976 result = []
1977 if (warnings):
1978 result.append(output_api.PresubmitPromptWarning(
1979 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571980 if (errors):
1981 result.append(output_api.PresubmitError(
1982 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311983 return result
1984
1985
[email protected]6c063c62012-07-11 19:11:061986def _CheckNoPragmaOnce(input_api, output_api):
1987 """Make sure that banned functions are not used."""
1988 files = []
1989 pattern = input_api.re.compile(r'^#pragma\s+once',
1990 input_api.re.MULTILINE)
1991 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1992 if not f.LocalPath().endswith('.h'):
1993 continue
1994 contents = input_api.ReadFile(f)
1995 if pattern.search(contents):
1996 files.append(f)
1997
1998 if files:
1999 return [output_api.PresubmitError(
2000 'Do not use #pragma once in header files.\n'
2001 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2002 files)]
2003 return []
2004
[email protected]127f18ec2012-06-16 05:05:592005
[email protected]e7479052012-09-19 00:26:122006def _CheckNoTrinaryTrueFalse(input_api, output_api):
2007 """Checks to make sure we don't introduce use of foo ? true : false."""
2008 problems = []
2009 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2010 for f in input_api.AffectedFiles():
2011 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2012 continue
2013
2014 for line_num, line in f.ChangedContents():
2015 if pattern.match(line):
2016 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2017
2018 if not problems:
2019 return []
2020 return [output_api.PresubmitPromptWarning(
2021 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2022 '\n'.join(problems))]
2023
2024
[email protected]55f9f382012-07-31 11:02:182025def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282026 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182027 change. Breaking - rules is an error, breaking ! rules is a
2028 warning.
2029 """
mohan.reddyf21db962014-10-16 12:26:472030 import sys
[email protected]55f9f382012-07-31 11:02:182031 # We need to wait until we have an input_api object and use this
2032 # roundabout construct to import checkdeps because this file is
2033 # eval-ed and thus doesn't have __file__.
2034 original_sys_path = sys.path
2035 try:
2036 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472037 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182038 import checkdeps
[email protected]55f9f382012-07-31 11:02:182039 from rules import Rule
2040 finally:
2041 # Restore sys.path to what it was before.
2042 sys.path = original_sys_path
2043
2044 added_includes = []
rhalavati08acd232017-04-03 07:23:282045 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242046 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182047 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062048 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502049 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082050 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062051 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502052 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082053 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062054 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502055 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082056 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182057
[email protected]26385172013-05-09 23:11:352058 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182059
2060 error_descriptions = []
2061 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282062 error_subjects = set()
2063 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182064 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2065 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082066 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182067 description_with_path = '%s\n %s' % (path, rule_description)
2068 if rule_type == Rule.DISALLOW:
2069 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282070 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182071 else:
2072 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282073 warning_subjects.add("#includes")
2074
2075 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2076 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082077 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282078 description_with_path = '%s\n %s' % (path, rule_description)
2079 if rule_type == Rule.DISALLOW:
2080 error_descriptions.append(description_with_path)
2081 error_subjects.add("imports")
2082 else:
2083 warning_descriptions.append(description_with_path)
2084 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182085
Jinsuk Kim5a092672017-10-24 22:42:242086 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022087 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082088 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242089 description_with_path = '%s\n %s' % (path, rule_description)
2090 if rule_type == Rule.DISALLOW:
2091 error_descriptions.append(description_with_path)
2092 error_subjects.add("imports")
2093 else:
2094 warning_descriptions.append(description_with_path)
2095 warning_subjects.add("imports")
2096
[email protected]55f9f382012-07-31 11:02:182097 results = []
2098 if error_descriptions:
2099 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282100 'You added one or more %s that violate checkdeps rules.'
2101 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182102 error_descriptions))
2103 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422104 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282105 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182106 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282107 '%s? See relevant DEPS file(s) for details and contacts.' %
2108 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182109 warning_descriptions))
2110 return results
2111
2112
[email protected]fbcafe5a2012-08-08 15:31:222113def _CheckFilePermissions(input_api, output_api):
2114 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152115 if input_api.platform == 'win32':
2116 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292117 checkperms_tool = input_api.os_path.join(
2118 input_api.PresubmitLocalPath(),
2119 'tools', 'checkperms', 'checkperms.py')
2120 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472121 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392122 with input_api.CreateTemporaryFile() as file_list:
2123 for f in input_api.AffectedFiles():
2124 # checkperms.py file/directory arguments must be relative to the
2125 # repository.
2126 file_list.write(f.LocalPath() + '\n')
2127 file_list.close()
2128 args += ['--file-list', file_list.name]
2129 try:
2130 input_api.subprocess.check_output(args)
2131 return []
2132 except input_api.subprocess.CalledProcessError as error:
2133 return [output_api.PresubmitError(
2134 'checkperms.py failed:',
2135 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222136
2137
robertocn832f5992017-01-04 19:01:302138def _CheckTeamTags(input_api, output_api):
2139 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2140 checkteamtags_tool = input_api.os_path.join(
2141 input_api.PresubmitLocalPath(),
2142 'tools', 'checkteamtags', 'checkteamtags.py')
2143 args = [input_api.python_executable, checkteamtags_tool,
2144 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222145 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302146 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2147 'OWNERS']
2148 try:
2149 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052150 warnings = input_api.subprocess.check_output(args + files).splitlines()
2151 if warnings:
2152 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302153 return []
2154 except input_api.subprocess.CalledProcessError as error:
2155 return [output_api.PresubmitError(
2156 'checkteamtags.py failed:',
2157 long_text=error.output)]
2158
2159
[email protected]c8278b32012-10-30 20:35:492160def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2161 """Makes sure we don't include ui/aura/window_property.h
2162 in header files.
2163 """
2164 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2165 errors = []
2166 for f in input_api.AffectedFiles():
2167 if not f.LocalPath().endswith('.h'):
2168 continue
2169 for line_num, line in f.ChangedContents():
2170 if pattern.match(line):
2171 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2172
2173 results = []
2174 if errors:
2175 results.append(output_api.PresubmitError(
2176 'Header files should not include ui/aura/window_property.h', errors))
2177 return results
2178
2179
[email protected]70ca77752012-11-20 03:45:032180def _CheckForVersionControlConflictsInFile(input_api, f):
2181 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2182 errors = []
2183 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162184 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232185 # First-level headers in markdown look a lot like version control
2186 # conflict markers. http://daringfireball.net/projects/markdown/basics
2187 continue
[email protected]70ca77752012-11-20 03:45:032188 if pattern.match(line):
2189 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2190 return errors
2191
2192
2193def _CheckForVersionControlConflicts(input_api, output_api):
2194 """Usually this is not intentional and will cause a compile failure."""
2195 errors = []
2196 for f in input_api.AffectedFiles():
2197 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2198
2199 results = []
2200 if errors:
2201 results.append(output_api.PresubmitError(
2202 'Version control conflict markers found, please resolve.', errors))
2203 return results
2204
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202205
estadee17314a02017-01-12 16:22:162206def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2207 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2208 errors = []
2209 for f in input_api.AffectedFiles():
2210 for line_num, line in f.ChangedContents():
2211 if pattern.search(line):
2212 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2213
2214 results = []
2215 if errors:
2216 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502217 'Found Google support URL addressed by answer number. Please replace '
2218 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162219 return results
2220
[email protected]70ca77752012-11-20 03:45:032221
[email protected]06e6d0ff2012-12-11 01:36:442222def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2223 def FilterFile(affected_file):
2224 """Filter function for use with input_api.AffectedSourceFiles,
2225 below. This filters out everything except non-test files from
2226 top-level directories that generally speaking should not hard-code
2227 service URLs (e.g. src/android_webview/, src/content/ and others).
2228 """
2229 return input_api.FilterSourceFile(
2230 affected_file,
Egor Paskoce145c42018-09-28 19:31:042231 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442232 black_list=(_EXCLUDED_PATHS +
2233 _TEST_CODE_EXCLUDED_PATHS +
2234 input_api.DEFAULT_BLACK_LIST))
2235
reillyi38965732015-11-16 18:27:332236 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2237 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462238 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2239 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442240 problems = [] # items are (filename, line_number, line)
2241 for f in input_api.AffectedSourceFiles(FilterFile):
2242 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462243 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442244 problems.append((f.LocalPath(), line_num, line))
2245
2246 if problems:
[email protected]f7051d52013-04-02 18:31:422247 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442248 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582249 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442250 [' %s:%d: %s' % (
2251 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032252 else:
2253 return []
[email protected]06e6d0ff2012-12-11 01:36:442254
2255
James Cook6b6597c2019-11-06 22:05:292256def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2257 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2258 def FileFilter(affected_file):
2259 """Includes directories known to be Chrome OS only."""
2260 return input_api.FilterSourceFile(
2261 affected_file,
2262 white_list=('^ash/',
2263 '^chromeos/', # Top-level src/chromeos.
2264 '/chromeos/', # Any path component.
2265 '^components/arc',
2266 '^components/exo'),
2267 black_list=(input_api.DEFAULT_BLACK_LIST))
2268
2269 prefs = []
2270 priority_prefs = []
2271 for f in input_api.AffectedFiles(file_filter=FileFilter):
2272 for line_num, line in f.ChangedContents():
2273 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2274 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2275 prefs.append(' %s' % line)
2276 if input_api.re.search(
2277 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2278 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2279 priority_prefs.append(' %s' % line)
2280
2281 results = []
2282 if (prefs):
2283 results.append(output_api.PresubmitPromptWarning(
2284 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2285 'by browser sync settings. If these prefs should be controlled by OS '
2286 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2287 if (priority_prefs):
2288 results.append(output_api.PresubmitPromptWarning(
2289 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2290 'controlled by browser sync settings. If these prefs should be '
2291 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2292 'instead.\n' + '\n'.join(prefs)))
2293 return results
2294
2295
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492296# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272297def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2298 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312299 The native_client_sdk directory is excluded because it has auto-generated PNG
2300 files for documentation.
[email protected]d2530012013-01-25 16:39:272301 """
[email protected]d2530012013-01-25 16:39:272302 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492303 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042304 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312305 file_filter = lambda f: input_api.FilterSourceFile(
2306 f, white_list=white_list, black_list=black_list)
2307 for f in input_api.AffectedFiles(include_deletes=False,
2308 file_filter=file_filter):
2309 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272310
2311 results = []
2312 if errors:
2313 results.append(output_api.PresubmitError(
2314 'The name of PNG files should not have abbreviations. \n'
2315 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2316 'Contact [email protected] if you have questions.', errors))
2317 return results
2318
2319
Daniel Cheng4dcdb6b2017-04-13 08:30:172320def _ExtractAddRulesFromParsedDeps(parsed_deps):
2321 """Extract the rules that add dependencies from a parsed DEPS file.
2322
2323 Args:
2324 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2325 add_rules = set()
2326 add_rules.update([
2327 rule[1:] for rule in parsed_deps.get('include_rules', [])
2328 if rule.startswith('+') or rule.startswith('!')
2329 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502330 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172331 {}).iteritems():
2332 add_rules.update([
2333 rule[1:] for rule in rules
2334 if rule.startswith('+') or rule.startswith('!')
2335 ])
2336 return add_rules
2337
2338
2339def _ParseDeps(contents):
2340 """Simple helper for parsing DEPS files."""
2341 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172342 class _VarImpl:
2343
2344 def __init__(self, local_scope):
2345 self._local_scope = local_scope
2346
2347 def Lookup(self, var_name):
2348 """Implements the Var syntax."""
2349 try:
2350 return self._local_scope['vars'][var_name]
2351 except KeyError:
2352 raise Exception('Var is not defined: %s' % var_name)
2353
2354 local_scope = {}
2355 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172356 'Var': _VarImpl(local_scope).Lookup,
2357 }
2358 exec contents in global_scope, local_scope
2359 return local_scope
2360
2361
2362def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082363 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412364 a set of DEPS entries that we should look up.
2365
2366 For a directory (rather than a specific filename) we fake a path to
2367 a specific filename by adding /DEPS. This is chosen as a file that
2368 will seldom or never be subject to per-file include_rules.
2369 """
[email protected]2b438d62013-11-14 17:54:142370 # We ignore deps entries on auto-generated directories.
2371 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082372
Daniel Cheng4dcdb6b2017-04-13 08:30:172373 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2374 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2375
2376 added_deps = new_deps.difference(old_deps)
2377
[email protected]2b438d62013-11-14 17:54:142378 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172379 for added_dep in added_deps:
2380 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2381 continue
2382 # Assume that a rule that ends in .h is a rule for a specific file.
2383 if added_dep.endswith('.h'):
2384 results.add(added_dep)
2385 else:
2386 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082387 return results
2388
2389
[email protected]e871964c2013-05-13 14:14:552390def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2391 """When a dependency prefixed with + is added to a DEPS file, we
2392 want to make sure that the change is reviewed by an OWNER of the
2393 target file or directory, to avoid layering violations from being
2394 introduced. This check verifies that this happens.
2395 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172396 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242397
2398 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492399 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242400 for f in input_api.AffectedFiles(include_deletes=False,
2401 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552402 filename = input_api.os_path.basename(f.LocalPath())
2403 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172404 virtual_depended_on_files.update(_CalculateAddedDeps(
2405 input_api.os_path,
2406 '\n'.join(f.OldContents()),
2407 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552408
[email protected]e871964c2013-05-13 14:14:552409 if not virtual_depended_on_files:
2410 return []
2411
2412 if input_api.is_committing:
2413 if input_api.tbr:
2414 return [output_api.PresubmitNotifyResult(
2415 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272416 if input_api.dry_run:
2417 return [output_api.PresubmitNotifyResult(
2418 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552419 if not input_api.change.issue:
2420 return [output_api.PresubmitError(
2421 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402422 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552423 output = output_api.PresubmitError
2424 else:
2425 output = output_api.PresubmitNotifyResult
2426
2427 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502428 owner_email, reviewers = (
2429 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2430 input_api,
2431 owners_db.email_regexp,
2432 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552433
2434 owner_email = owner_email or input_api.change.author_email
2435
[email protected]de4f7d22013-05-23 14:27:462436 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512437 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462438 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552439 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2440 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412441
2442 # We strip the /DEPS part that was added by
2443 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2444 # directory.
2445 def StripDeps(path):
2446 start_deps = path.rfind('/DEPS')
2447 if start_deps != -1:
2448 return path[:start_deps]
2449 else:
2450 return path
2451 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552452 for path in missing_files]
2453
2454 if unapproved_dependencies:
2455 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152456 output('You need LGTM from owners of depends-on paths in DEPS that were '
2457 'modified in this CL:\n %s' %
2458 '\n '.join(sorted(unapproved_dependencies)))]
2459 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2460 output_list.append(output(
2461 'Suggested missing target path OWNERS:\n %s' %
2462 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552463 return output_list
2464
2465 return []
2466
2467
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492468# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402469def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492470 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402471 black_list = (_EXCLUDED_PATHS +
2472 _TEST_CODE_EXCLUDED_PATHS +
2473 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042474 (r"^base[\\/]logging\.h$",
2475 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222476 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042477 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2478 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2479 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122480 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182481 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152482 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032483 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152484 r"^chrome[\\/]chrome_cleaner[\\/].*",
2485 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2486 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042487 r"^chromecast[\\/]",
2488 r"^cloud_print[\\/]",
2489 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482490 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052491 r"^components[\\/]media_control[\\/]renderer[\\/]"
2492 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042493 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462494 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042495 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462496 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042497 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252498 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042499 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2500 r"^courgette[\\/]courgette_tool\.cc$",
2501 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272502 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002503 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332504 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042505 r"^ipc[\\/]ipc_logging\.cc$",
2506 r"^native_client_sdk[\\/]",
2507 r"^remoting[\\/]base[\\/]logging\.h$",
2508 r"^remoting[\\/]host[\\/].*",
2509 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062510 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332511 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042512 r"^tools[\\/]",
2513 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2514 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Shahbaz Youssefi1b473182020-06-10 18:05:252515 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402516 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492517 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402518
thomasanderson625d3932017-03-29 07:16:582519 log_info = set([])
2520 printf = set([])
[email protected]85218562013-11-22 07:41:402521
2522 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582523 for _, line in f.ChangedContents():
2524 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2525 log_info.add(f.LocalPath())
2526 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2527 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372528
thomasanderson625d3932017-03-29 07:16:582529 if input_api.re.search(r"\bprintf\(", line):
2530 printf.add(f.LocalPath())
2531 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2532 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402533
2534 if log_info:
2535 return [output_api.PresubmitError(
2536 'These files spam the console log with LOG(INFO):',
2537 items=log_info)]
2538 if printf:
2539 return [output_api.PresubmitError(
2540 'These files spam the console log with printf/fprintf:',
2541 items=printf)]
2542 return []
2543
2544
[email protected]49aa76a2013-12-04 06:59:162545def _CheckForAnonymousVariables(input_api, output_api):
2546 """These types are all expected to hold locks while in scope and
2547 so should never be anonymous (which causes them to be immediately
2548 destroyed)."""
2549 they_who_must_be_named = [
2550 'base::AutoLock',
2551 'base::AutoReset',
2552 'base::AutoUnlock',
2553 'SkAutoAlphaRestore',
2554 'SkAutoBitmapShaderInstall',
2555 'SkAutoBlitterChoose',
2556 'SkAutoBounderCommit',
2557 'SkAutoCallProc',
2558 'SkAutoCanvasRestore',
2559 'SkAutoCommentBlock',
2560 'SkAutoDescriptor',
2561 'SkAutoDisableDirectionCheck',
2562 'SkAutoDisableOvalCheck',
2563 'SkAutoFree',
2564 'SkAutoGlyphCache',
2565 'SkAutoHDC',
2566 'SkAutoLockColors',
2567 'SkAutoLockPixels',
2568 'SkAutoMalloc',
2569 'SkAutoMaskFreeImage',
2570 'SkAutoMutexAcquire',
2571 'SkAutoPathBoundsUpdate',
2572 'SkAutoPDFRelease',
2573 'SkAutoRasterClipValidate',
2574 'SkAutoRef',
2575 'SkAutoTime',
2576 'SkAutoTrace',
2577 'SkAutoUnref',
2578 ]
2579 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2580 # bad: base::AutoLock(lock.get());
2581 # not bad: base::AutoLock lock(lock.get());
2582 bad_pattern = input_api.re.compile(anonymous)
2583 # good: new base::AutoLock(lock.get())
2584 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2585 errors = []
2586
2587 for f in input_api.AffectedFiles():
2588 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2589 continue
2590 for linenum, line in f.ChangedContents():
2591 if bad_pattern.search(line) and not good_pattern.search(line):
2592 errors.append('%s:%d' % (f.LocalPath(), linenum))
2593
2594 if errors:
2595 return [output_api.PresubmitError(
2596 'These lines create anonymous variables that need to be named:',
2597 items=errors)]
2598 return []
2599
2600
Peter Kasting4844e46e2018-02-23 07:27:102601def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532602 # Returns whether |template_str| is of the form <T, U...> for some types T
2603 # and U. Assumes that |template_str| is already in the form <...>.
2604 def HasMoreThanOneArg(template_str):
2605 # Level of <...> nesting.
2606 nesting = 0
2607 for c in template_str:
2608 if c == '<':
2609 nesting += 1
2610 elif c == '>':
2611 nesting -= 1
2612 elif c == ',' and nesting == 1:
2613 return True
2614 return False
2615
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492616 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102617 sources = lambda affected_file: input_api.FilterSourceFile(
2618 affected_file,
2619 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2620 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492621 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552622
2623 # Pattern to capture a single "<...>" block of template arguments. It can
2624 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2625 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2626 # latter would likely require counting that < and > match, which is not
2627 # expressible in regular languages. Should the need arise, one can introduce
2628 # limited counting (matching up to a total number of nesting depth), which
2629 # should cover all practical cases for already a low nesting limit.
2630 template_arg_pattern = (
2631 r'<[^>]*' # Opening block of <.
2632 r'>([^<]*>)?') # Closing block of >.
2633 # Prefix expressing that whatever follows is not already inside a <...>
2634 # block.
2635 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102636 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552637 not_inside_template_arg_pattern
2638 + r'\bstd::unique_ptr'
2639 + template_arg_pattern
2640 + r'\(\)')
2641
2642 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2643 template_arg_no_array_pattern = (
2644 r'<[^>]*[^]]' # Opening block of <.
2645 r'>([^(<]*[^]]>)?') # Closing block of >.
2646 # Prefix saying that what follows is the start of an expression.
2647 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2648 # Suffix saying that what follows are call parentheses with a non-empty list
2649 # of arguments.
2650 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532651 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552652 return_construct_pattern = input_api.re.compile(
2653 start_of_expr_pattern
2654 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532655 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552656 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532657 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552658 + nonempty_arg_list_pattern)
2659
Vaclav Brozek851d9602018-04-04 16:13:052660 problems_constructor = []
2661 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102662 for f in input_api.AffectedSourceFiles(sources):
2663 for line_number, line in f.ChangedContents():
2664 # Disallow:
2665 # return std::unique_ptr<T>(foo);
2666 # bar = std::unique_ptr<T>(foo);
2667 # But allow:
2668 # return std::unique_ptr<T[]>(foo);
2669 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532670 # And also allow cases when the second template argument is present. Those
2671 # cases cannot be handled by std::make_unique:
2672 # return std::unique_ptr<T, U>(foo);
2673 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052674 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532675 return_construct_result = return_construct_pattern.search(line)
2676 if return_construct_result and not HasMoreThanOneArg(
2677 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052678 problems_constructor.append(
2679 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102680 # Disallow:
2681 # std::unique_ptr<T>()
2682 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052683 problems_nullptr.append(
2684 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2685
2686 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162687 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052688 errors.append(output_api.PresubmitError(
2689 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162690 problems_nullptr))
2691 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052692 errors.append(output_api.PresubmitError(
2693 'The following files use explicit std::unique_ptr constructor.'
2694 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162695 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102696 return errors
2697
2698
[email protected]999261d2014-03-03 20:08:082699def _CheckUserActionUpdate(input_api, output_api):
2700 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522701 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082702 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522703 # If actions.xml is already included in the changelist, the PRESUBMIT
2704 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082705 return []
2706
[email protected]999261d2014-03-03 20:08:082707 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2708 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522709 current_actions = None
[email protected]999261d2014-03-03 20:08:082710 for f in input_api.AffectedFiles(file_filter=file_filter):
2711 for line_num, line in f.ChangedContents():
2712 match = input_api.re.search(action_re, line)
2713 if match:
[email protected]2f92dec2014-03-07 19:21:522714 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2715 # loaded only once.
2716 if not current_actions:
2717 with open('tools/metrics/actions/actions.xml') as actions_f:
2718 current_actions = actions_f.read()
2719 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082720 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522721 action = 'name="{0}"'.format(action_name)
2722 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082723 return [output_api.PresubmitPromptWarning(
2724 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522725 'tools/metrics/actions/actions.xml. Please run '
2726 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082727 % (f.LocalPath(), line_num, action_name))]
2728 return []
2729
2730
Daniel Cheng13ca61a882017-08-25 15:11:252731def _ImportJSONCommentEater(input_api):
2732 import sys
2733 sys.path = sys.path + [input_api.os_path.join(
2734 input_api.PresubmitLocalPath(),
2735 'tools', 'json_comment_eater')]
2736 import json_comment_eater
2737 return json_comment_eater
2738
2739
[email protected]99171a92014-06-03 08:44:472740def _GetJSONParseError(input_api, filename, eat_comments=True):
2741 try:
2742 contents = input_api.ReadFile(filename)
2743 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252744 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132745 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472746
2747 input_api.json.loads(contents)
2748 except ValueError as e:
2749 return e
2750 return None
2751
2752
2753def _GetIDLParseError(input_api, filename):
2754 try:
2755 contents = input_api.ReadFile(filename)
2756 idl_schema = input_api.os_path.join(
2757 input_api.PresubmitLocalPath(),
2758 'tools', 'json_schema_compiler', 'idl_schema.py')
2759 process = input_api.subprocess.Popen(
2760 [input_api.python_executable, idl_schema],
2761 stdin=input_api.subprocess.PIPE,
2762 stdout=input_api.subprocess.PIPE,
2763 stderr=input_api.subprocess.PIPE,
2764 universal_newlines=True)
2765 (_, error) = process.communicate(input=contents)
2766 return error or None
2767 except ValueError as e:
2768 return e
2769
2770
2771def _CheckParseErrors(input_api, output_api):
2772 """Check that IDL and JSON files do not contain syntax errors."""
2773 actions = {
2774 '.idl': _GetIDLParseError,
2775 '.json': _GetJSONParseError,
2776 }
[email protected]99171a92014-06-03 08:44:472777 # Most JSON files are preprocessed and support comments, but these do not.
2778 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042779 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472780 ]
2781 # Only run IDL checker on files in these directories.
2782 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042783 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2784 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472785 ]
2786
2787 def get_action(affected_file):
2788 filename = affected_file.LocalPath()
2789 return actions.get(input_api.os_path.splitext(filename)[1])
2790
[email protected]99171a92014-06-03 08:44:472791 def FilterFile(affected_file):
2792 action = get_action(affected_file)
2793 if not action:
2794 return False
2795 path = affected_file.LocalPath()
2796
Erik Staab2dd72b12020-04-16 15:03:402797 if _MatchesFile(input_api,
2798 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2799 path):
[email protected]99171a92014-06-03 08:44:472800 return False
2801
2802 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162803 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472804 return False
2805 return True
2806
2807 results = []
2808 for affected_file in input_api.AffectedFiles(
2809 file_filter=FilterFile, include_deletes=False):
2810 action = get_action(affected_file)
2811 kwargs = {}
2812 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162813 _MatchesFile(input_api, json_no_comments_patterns,
2814 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472815 kwargs['eat_comments'] = False
2816 parse_error = action(input_api,
2817 affected_file.AbsoluteLocalPath(),
2818 **kwargs)
2819 if parse_error:
2820 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2821 (affected_file.LocalPath(), parse_error)))
2822 return results
2823
2824
[email protected]760deea2013-12-10 19:33:492825def _CheckJavaStyle(input_api, output_api):
2826 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472827 import sys
[email protected]760deea2013-12-10 19:33:492828 original_sys_path = sys.path
2829 try:
2830 sys.path = sys.path + [input_api.os_path.join(
2831 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2832 import checkstyle
2833 finally:
2834 # Restore sys.path to what it was before.
2835 sys.path = original_sys_path
2836
2837 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092838 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512839 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492840
2841
Nate Fischerdfd9812e2019-07-18 22:03:002842def _CheckPythonDevilInit(input_api, output_api):
2843 """Checks to make sure devil is initialized correctly in python scripts."""
2844 script_common_initialize_pattern = input_api.re.compile(
2845 r'script_common\.InitializeEnvironment\(')
2846 devil_env_config_initialize = input_api.re.compile(
2847 r'devil_env\.config\.Initialize\(')
2848
2849 errors = []
2850
2851 sources = lambda affected_file: input_api.FilterSourceFile(
2852 affected_file,
2853 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2854 (r'^build[\\/]android[\\/]devil_chromium\.py',
2855 r'^third_party[\\/].*',)),
2856 white_list=[r'.*\.py$'])
2857
2858 for f in input_api.AffectedSourceFiles(sources):
2859 for line_num, line in f.ChangedContents():
2860 if (script_common_initialize_pattern.search(line) or
2861 devil_env_config_initialize.search(line)):
2862 errors.append("%s:%d" % (f.LocalPath(), line_num))
2863
2864 results = []
2865
2866 if errors:
2867 results.append(output_api.PresubmitError(
2868 'Devil initialization should always be done using '
2869 'devil_chromium.Initialize() in the chromium project, to use better '
2870 'defaults for dependencies (ex. up-to-date version of adb).',
2871 errors))
2872
2873 return results
2874
2875
Sean Kau46e29bc2017-08-28 16:31:162876def _MatchesFile(input_api, patterns, path):
2877 for pattern in patterns:
2878 if input_api.re.search(pattern, path):
2879 return True
2880 return False
2881
2882
Daniel Cheng7052cdf2017-11-21 19:23:292883def _GetOwnersFilesToCheckForIpcOwners(input_api):
2884 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172885
Daniel Cheng7052cdf2017-11-21 19:23:292886 Returns:
2887 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2888 contain to cover IPC-related files with noparent reviewer rules.
2889 """
2890 # Whether or not a file affects IPC is (mostly) determined by a simple list
2891 # of filename patterns.
dchenge07de812016-06-20 19:27:172892 file_patterns = [
palmerb19a0932017-01-24 04:00:312893 # Legacy IPC:
dchenge07de812016-06-20 19:27:172894 '*_messages.cc',
2895 '*_messages*.h',
2896 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312897 # Mojo IPC:
dchenge07de812016-06-20 19:27:172898 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472899 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172900 '*_struct_traits*.*',
2901 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312902 '*.typemap',
2903 # Android native IPC:
2904 '*.aidl',
2905 # Blink uses a different file naming convention:
2906 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472907 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172908 '*StructTraits*.*',
2909 '*TypeConverter*.*',
2910 ]
2911
scottmg7a6ed5ba2016-11-04 18:22:042912 # These third_party directories do not contain IPCs, but contain files
2913 # matching the above patterns, which trigger false positives.
2914 exclude_paths = [
2915 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162916 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232917 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292918 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542919 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162920 # These files are just used to communicate between class loaders running
2921 # in the same process.
2922 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572923 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2924
scottmg7a6ed5ba2016-11-04 18:22:042925 ]
2926
dchenge07de812016-06-20 19:27:172927 # Dictionary mapping an OWNERS file path to Patterns.
2928 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2929 # rules ) to a PatternEntry.
2930 # PatternEntry is a dictionary with two keys:
2931 # - 'files': the files that are matched by this pattern
2932 # - 'rules': the per-file rules needed for this pattern
2933 # For example, if we expect OWNERS file to contain rules for *.mojom and
2934 # *_struct_traits*.*, Patterns might look like this:
2935 # {
2936 # '*.mojom': {
2937 # 'files': ...,
2938 # 'rules': [
2939 # 'per-file *.mojom=set noparent',
2940 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2941 # ],
2942 # },
2943 # '*_struct_traits*.*': {
2944 # 'files': ...,
2945 # 'rules': [
2946 # 'per-file *_struct_traits*.*=set noparent',
2947 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2948 # ],
2949 # },
2950 # }
2951 to_check = {}
2952
Daniel Cheng13ca61a882017-08-25 15:11:252953 def AddPatternToCheck(input_file, pattern):
2954 owners_file = input_api.os_path.join(
2955 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2956 if owners_file not in to_check:
2957 to_check[owners_file] = {}
2958 if pattern not in to_check[owners_file]:
2959 to_check[owners_file][pattern] = {
2960 'files': [],
2961 'rules': [
2962 'per-file %s=set noparent' % pattern,
2963 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2964 ]
2965 }
Vaclav Brozekd5de76a2018-03-17 07:57:502966 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252967
dchenge07de812016-06-20 19:27:172968 # Iterate through the affected files to see what we actually need to check
2969 # for. We should only nag patch authors about per-file rules if a file in that
2970 # directory would match that pattern. If a directory only contains *.mojom
2971 # files and no *_messages*.h files, we should only nag about rules for
2972 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252973 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262974 # Manifest files don't have a strong naming convention. Instead, try to find
2975 # affected .cc and .h files which look like they contain a manifest
2976 # definition.
2977 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2978 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2979 if (manifest_pattern.search(f.LocalPath()) and not
2980 test_manifest_pattern.search(f.LocalPath())):
2981 # We expect all actual service manifest files to contain at least one
2982 # qualified reference to service_manager::Manifest.
2983 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252984 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172985 for pattern in file_patterns:
2986 if input_api.fnmatch.fnmatch(
2987 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042988 skip = False
2989 for exclude in exclude_paths:
2990 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2991 skip = True
2992 break
2993 if skip:
2994 continue
Daniel Cheng13ca61a882017-08-25 15:11:252995 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172996 break
2997
Daniel Cheng7052cdf2017-11-21 19:23:292998 return to_check
2999
3000
Wez17c66962020-04-29 15:26:033001def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3002 """Adds OWNERS files to check for correct Fuchsia security owners."""
3003
3004 file_patterns = [
3005 # Component specifications.
3006 '*.cml', # Component Framework v2.
3007 '*.cmx', # Component Framework v1.
3008
3009 # Fuchsia IDL protocol specifications.
3010 '*.fidl',
3011 ]
3012
3013 def AddPatternToCheck(input_file, pattern):
3014 owners_file = input_api.os_path.join(
3015 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3016 if owners_file not in to_check:
3017 to_check[owners_file] = {}
3018 if pattern not in to_check[owners_file]:
3019 to_check[owners_file][pattern] = {
3020 'files': [],
3021 'rules': [
3022 'per-file %s=set noparent' % pattern,
3023 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3024 ]
3025 }
3026 to_check[owners_file][pattern]['files'].append(input_file)
3027
3028 # Iterate through the affected files to see what we actually need to check
3029 # for. We should only nag patch authors about per-file rules if a file in that
3030 # directory would match that pattern.
3031 for f in input_api.AffectedFiles(include_deletes=False):
3032 for pattern in file_patterns:
3033 if input_api.fnmatch.fnmatch(
3034 input_api.os_path.basename(f.LocalPath()), pattern):
3035 AddPatternToCheck(f, pattern)
3036 break
3037
3038 return to_check
3039
3040
3041def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293042 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3043 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033044 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293045
3046 if to_check:
3047 # If there are any OWNERS files to check, there are IPC-related changes in
3048 # this CL. Auto-CC the review list.
3049 output_api.AppendCC('[email protected]')
3050
3051 # Go through the OWNERS files to check, filtering out rules that are already
3052 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173053 for owners_file, patterns in to_check.iteritems():
3054 try:
3055 with file(owners_file) as f:
3056 lines = set(f.read().splitlines())
3057 for entry in patterns.itervalues():
3058 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3059 ]
3060 except IOError:
3061 # No OWNERS file, so all the rules are definitely missing.
3062 continue
3063
3064 # All the remaining lines weren't found in OWNERS files, so emit an error.
3065 errors = []
3066 for owners_file, patterns in to_check.iteritems():
3067 missing_lines = []
3068 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503069 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173070 missing_lines.extend(entry['rules'])
3071 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3072 if missing_lines:
3073 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053074 'Because of the presence of files:\n%s\n\n'
3075 '%s needs the following %d lines added:\n\n%s' %
3076 ('\n'.join(files), owners_file, len(missing_lines),
3077 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173078
3079 results = []
3080 if errors:
vabrf5ce3bf92016-07-11 14:52:413081 if input_api.is_committing:
3082 output = output_api.PresubmitError
3083 else:
3084 output = output_api.PresubmitPromptWarning
3085 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593086 'Found OWNERS files that need to be updated for IPC security ' +
3087 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173088 long_text='\n\n'.join(errors)))
3089
3090 return results
3091
3092
Robert Sesek2c905332020-05-06 23:17:133093def _GetFilesUsingSecurityCriticalFunctions(input_api):
3094 """Checks affected files for changes to security-critical calls. This
3095 function checks the full change diff, to catch both additions/changes
3096 and removals.
3097
3098 Returns a dict keyed by file name, and the value is a set of detected
3099 functions.
3100 """
3101 # Map of function pretty name (displayed in an error) to the pattern to
3102 # match it with.
3103 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373104 'content::GetServiceSandboxType<>()':
3105 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133106 }
3107 _PATTERNS_TO_CHECK = {
3108 k: input_api.re.compile(v)
3109 for k, v in _PATTERNS_TO_CHECK.items()
3110 }
3111
3112 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3113 files_to_functions = {}
3114 for f in input_api.AffectedFiles():
3115 diff = f.GenerateScmDiff()
3116 for line in diff.split('\n'):
3117 # Not using just RightHandSideLines() because removing a
3118 # call to a security-critical function can be just as important
3119 # as adding or changing the arguments.
3120 if line.startswith('-') or (line.startswith('+') and
3121 not line.startswith('++')):
3122 for name, pattern in _PATTERNS_TO_CHECK.items():
3123 if pattern.search(line):
3124 path = f.LocalPath()
3125 if not path in files_to_functions:
3126 files_to_functions[path] = set()
3127 files_to_functions[path].add(name)
3128 return files_to_functions
3129
3130
3131def _CheckSecurityChanges(input_api, output_api):
3132 """Checks that changes involving security-critical functions are reviewed
3133 by the security team.
3134 """
3135 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3136 if len(files_to_functions):
3137 owners_db = input_api.owners_db
3138 owner_email, reviewers = (
3139 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3140 input_api,
3141 owners_db.email_regexp,
3142 approval_needed=input_api.is_committing))
3143
3144 # Load the OWNERS file for security changes.
3145 owners_file = 'ipc/SECURITY_OWNERS'
3146 security_owners = owners_db.owners_rooted_at_file(owners_file)
3147
3148 has_security_owner = any([owner in reviewers for owner in security_owners])
3149 if not has_security_owner:
3150 msg = 'The following files change calls to security-sensive functions\n' \
3151 'that need to be reviewed by {}.\n'.format(owners_file)
3152 for path, names in files_to_functions.items():
3153 msg += ' {}\n'.format(path)
3154 for name in names:
3155 msg += ' {}\n'.format(name)
3156 msg += '\n'
3157
3158 if input_api.is_committing:
3159 output = output_api.PresubmitError
3160 else:
3161 output = output_api.PresubmitNotifyResult
3162 return [output(msg)]
3163
3164 return []
3165
3166
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263167def _CheckSetNoParent(input_api, output_api):
3168 """Checks that set noparent is only used together with an OWNERS file in
3169 //build/OWNERS.setnoparent (see also
3170 //docs/code_reviews.md#owners-files-details)
3171 """
3172 errors = []
3173
3174 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3175 allowed_owners_files = set()
3176 with open(allowed_owners_files_file, 'r') as f:
3177 for line in f:
3178 line = line.strip()
3179 if not line or line.startswith('#'):
3180 continue
3181 allowed_owners_files.add(line)
3182
3183 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3184
3185 for f in input_api.AffectedFiles(include_deletes=False):
3186 if not f.LocalPath().endswith('OWNERS'):
3187 continue
3188
3189 found_owners_files = set()
3190 found_set_noparent_lines = dict()
3191
3192 # Parse the OWNERS file.
3193 for lineno, line in enumerate(f.NewContents(), 1):
3194 line = line.strip()
3195 if line.startswith('set noparent'):
3196 found_set_noparent_lines[''] = lineno
3197 if line.startswith('file://'):
3198 if line in allowed_owners_files:
3199 found_owners_files.add('')
3200 if line.startswith('per-file'):
3201 match = per_file_pattern.match(line)
3202 if match:
3203 glob = match.group(1).strip()
3204 directive = match.group(2).strip()
3205 if directive == 'set noparent':
3206 found_set_noparent_lines[glob] = lineno
3207 if directive.startswith('file://'):
3208 if directive in allowed_owners_files:
3209 found_owners_files.add(glob)
3210
3211 # Check that every set noparent line has a corresponding file:// line
3212 # listed in build/OWNERS.setnoparent.
3213 for set_noparent_line in found_set_noparent_lines:
3214 if set_noparent_line in found_owners_files:
3215 continue
3216 errors.append(' %s:%d' % (f.LocalPath(),
3217 found_set_noparent_lines[set_noparent_line]))
3218
3219 results = []
3220 if errors:
3221 if input_api.is_committing:
3222 output = output_api.PresubmitError
3223 else:
3224 output = output_api.PresubmitPromptWarning
3225 results.append(output(
3226 'Found the following "set noparent" restrictions in OWNERS files that '
3227 'do not include owners from build/OWNERS.setnoparent:',
3228 long_text='\n\n'.join(errors)))
3229 return results
3230
3231
jbriance9e12f162016-11-25 07:57:503232def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313233 """Checks that added or removed lines in non third party affected
3234 header files do not lead to new useless class or struct forward
3235 declaration.
jbriance9e12f162016-11-25 07:57:503236 """
3237 results = []
3238 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3239 input_api.re.MULTILINE)
3240 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3241 input_api.re.MULTILINE)
3242 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313243 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193244 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493245 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313246 continue
3247
jbriance9e12f162016-11-25 07:57:503248 if not f.LocalPath().endswith('.h'):
3249 continue
3250
3251 contents = input_api.ReadFile(f)
3252 fwd_decls = input_api.re.findall(class_pattern, contents)
3253 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3254
3255 useless_fwd_decls = []
3256 for decl in fwd_decls:
3257 count = sum(1 for _ in input_api.re.finditer(
3258 r'\b%s\b' % input_api.re.escape(decl), contents))
3259 if count == 1:
3260 useless_fwd_decls.append(decl)
3261
3262 if not useless_fwd_decls:
3263 continue
3264
3265 for line in f.GenerateScmDiff().splitlines():
3266 if (line.startswith('-') and not line.startswith('--') or
3267 line.startswith('+') and not line.startswith('++')):
3268 for decl in useless_fwd_decls:
3269 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3270 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243271 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503272 (f.LocalPath(), decl)))
3273 useless_fwd_decls.remove(decl)
3274
3275 return results
3276
Jinsong Fan91ebbbd2019-04-16 14:57:173277def _CheckAndroidDebuggableBuild(input_api, output_api):
3278 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3279 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3280 this is a debuggable build of Android.
3281 """
3282 build_type_check_pattern = input_api.re.compile(
3283 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3284
3285 errors = []
3286
3287 sources = lambda affected_file: input_api.FilterSourceFile(
3288 affected_file,
3289 black_list=(_EXCLUDED_PATHS +
3290 _TEST_CODE_EXCLUDED_PATHS +
3291 input_api.DEFAULT_BLACK_LIST +
3292 (r"^android_webview[\\/]support_library[\\/]"
3293 "boundary_interfaces[\\/]",
3294 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3295 r'^third_party[\\/].*',
3296 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3297 r"webview[\\/]chromium[\\/]License.*",)),
3298 white_list=[r'.*\.java$'])
3299
3300 for f in input_api.AffectedSourceFiles(sources):
3301 for line_num, line in f.ChangedContents():
3302 if build_type_check_pattern.search(line):
3303 errors.append("%s:%d" % (f.LocalPath(), line_num))
3304
3305 results = []
3306
3307 if errors:
3308 results.append(output_api.PresubmitPromptWarning(
3309 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3310 ' Please use BuildInfo.isDebugAndroid() instead.',
3311 errors))
3312
3313 return results
jbriance9e12f162016-11-25 07:57:503314
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493315# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293316def _CheckAndroidToastUsage(input_api, output_api):
3317 """Checks that code uses org.chromium.ui.widget.Toast instead of
3318 android.widget.Toast (Chromium Toast doesn't force hardware
3319 acceleration on low-end devices, saving memory).
3320 """
3321 toast_import_pattern = input_api.re.compile(
3322 r'^import android\.widget\.Toast;$')
3323
3324 errors = []
3325
3326 sources = lambda affected_file: input_api.FilterSourceFile(
3327 affected_file,
3328 black_list=(_EXCLUDED_PATHS +
3329 _TEST_CODE_EXCLUDED_PATHS +
3330 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043331 (r'^chromecast[\\/].*',
3332 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493333 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293334
3335 for f in input_api.AffectedSourceFiles(sources):
3336 for line_num, line in f.ChangedContents():
3337 if toast_import_pattern.search(line):
3338 errors.append("%s:%d" % (f.LocalPath(), line_num))
3339
3340 results = []
3341
3342 if errors:
3343 results.append(output_api.PresubmitError(
3344 'android.widget.Toast usage is detected. Android toasts use hardware'
3345 ' acceleration, and can be\ncostly on low-end devices. Please use'
3346 ' org.chromium.ui.widget.Toast instead.\n'
3347 'Contact [email protected] if you have any questions.',
3348 errors))
3349
3350 return results
3351
3352
dgnaa68d5e2015-06-10 10:08:223353def _CheckAndroidCrLogUsage(input_api, output_api):
3354 """Checks that new logs using org.chromium.base.Log:
3355 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513356 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223357 """
pkotwicza1dd0b002016-05-16 14:41:043358
torne89540622017-03-24 19:41:303359 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043360 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303361 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043362 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303363 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043364 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3365 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093366 # The customtabs_benchmark is a small app that does not depend on Chromium
3367 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043368 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043369 ]
3370
dgnaa68d5e2015-06-10 10:08:223371 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123372 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3373 class_in_base_pattern = input_api.re.compile(
3374 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3375 has_some_log_import_pattern = input_api.re.compile(
3376 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223377 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553378 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223379 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463380 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553381 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223382
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463383 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493384 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043385 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123386
dgnaa68d5e2015-06-10 10:08:223387 tag_decl_errors = []
3388 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123389 tag_errors = []
dgn38736db2015-09-18 19:20:513390 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123391 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223392
3393 for f in input_api.AffectedSourceFiles(sources):
3394 file_content = input_api.ReadFile(f)
3395 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223396 # Per line checks
dgn87d9fb62015-06-12 09:15:123397 if (cr_log_import_pattern.search(file_content) or
3398 (class_in_base_pattern.search(file_content) and
3399 not has_some_log_import_pattern.search(file_content))):
3400 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223401 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553402 if rough_log_decl_pattern.search(line):
3403 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223404
3405 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123406 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223407 if match:
3408 has_modified_logs = True
3409
3410 # Make sure it uses "TAG"
3411 if not match.group('tag') == 'TAG':
3412 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123413 else:
3414 # Report non cr Log function calls in changed lines
3415 for line_num, line in f.ChangedContents():
3416 if log_call_pattern.search(line):
3417 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223418
3419 # Per file checks
3420 if has_modified_logs:
3421 # Make sure the tag is using the "cr" prefix and is not too long
3422 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513423 tag_name = match.group('name') if match else None
3424 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223425 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513426 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223427 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513428 elif '.' in tag_name:
3429 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223430
3431 results = []
3432 if tag_decl_errors:
3433 results.append(output_api.PresubmitPromptWarning(
3434 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513435 '"private static final String TAG = "<package tag>".\n'
3436 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223437 tag_decl_errors))
3438
3439 if tag_length_errors:
3440 results.append(output_api.PresubmitError(
3441 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513442 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223443 tag_length_errors))
3444
3445 if tag_errors:
3446 results.append(output_api.PresubmitPromptWarning(
3447 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3448 tag_errors))
3449
dgn87d9fb62015-06-12 09:15:123450 if util_log_errors:
dgn4401aa52015-04-29 16:26:173451 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123452 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3453 util_log_errors))
3454
dgn38736db2015-09-18 19:20:513455 if tag_with_dot_errors:
3456 results.append(output_api.PresubmitPromptWarning(
3457 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3458 tag_with_dot_errors))
3459
dgn4401aa52015-04-29 16:26:173460 return results
3461
3462
Yoland Yanb92fa522017-08-28 17:37:063463def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3464 """Checks that junit.framework.* is no longer used."""
3465 deprecated_junit_framework_pattern = input_api.re.compile(
3466 r'^import junit\.framework\..*;',
3467 input_api.re.MULTILINE)
3468 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493469 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063470 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133471 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063472 for line_num, line in f.ChangedContents():
3473 if deprecated_junit_framework_pattern.search(line):
3474 errors.append("%s:%d" % (f.LocalPath(), line_num))
3475
3476 results = []
3477 if errors:
3478 results.append(output_api.PresubmitError(
3479 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3480 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3481 ' if you have any question.', errors))
3482 return results
3483
3484
3485def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3486 """Checks that if new Java test classes have inheritance.
3487 Either the new test class is JUnit3 test or it is a JUnit4 test class
3488 with a base class, either case is undesirable.
3489 """
3490 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3491
3492 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493493 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063494 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133495 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063496 if not f.OldContents():
3497 class_declaration_start_flag = False
3498 for line_num, line in f.ChangedContents():
3499 if class_declaration_pattern.search(line):
3500 class_declaration_start_flag = True
3501 if class_declaration_start_flag and ' extends ' in line:
3502 errors.append('%s:%d' % (f.LocalPath(), line_num))
3503 if '{' in line:
3504 class_declaration_start_flag = False
3505
3506 results = []
3507 if errors:
3508 results.append(output_api.PresubmitPromptWarning(
3509 'The newly created files include Test classes that inherits from base'
3510 ' class. Please do not use inheritance in JUnit4 tests or add new'
3511 ' JUnit3 tests. Contact [email protected] if you have any'
3512 ' questions.', errors))
3513 return results
3514
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203515
yolandyan45001472016-12-21 21:12:423516def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3517 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3518 deprecated_annotation_import_pattern = input_api.re.compile(
3519 r'^import android\.test\.suitebuilder\.annotation\..*;',
3520 input_api.re.MULTILINE)
3521 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493522 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423523 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133524 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423525 for line_num, line in f.ChangedContents():
3526 if deprecated_annotation_import_pattern.search(line):
3527 errors.append("%s:%d" % (f.LocalPath(), line_num))
3528
3529 results = []
3530 if errors:
3531 results.append(output_api.PresubmitError(
3532 'Annotations in android.test.suitebuilder.annotation have been'
3533 ' deprecated since API level 24. Please use android.support.test.filters'
3534 ' from //third_party/android_support_test_runner:runner_java instead.'
3535 ' Contact [email protected] if you have any questions.', errors))
3536 return results
3537
3538
agrieve7b6479d82015-10-07 14:24:223539def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3540 """Checks if MDPI assets are placed in a correct directory."""
3541 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3542 ('/res/drawable/' in f.LocalPath() or
3543 '/res/drawable-ldrtl/' in f.LocalPath()))
3544 errors = []
3545 for f in input_api.AffectedFiles(include_deletes=False,
3546 file_filter=file_filter):
3547 errors.append(' %s' % f.LocalPath())
3548
3549 results = []
3550 if errors:
3551 results.append(output_api.PresubmitError(
3552 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3553 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3554 '/res/drawable-ldrtl/.\n'
3555 'Contact [email protected] if you have questions.', errors))
3556 return results
3557
3558
Nate Fischer535972b2017-09-16 01:06:183559def _CheckAndroidWebkitImports(input_api, output_api):
3560 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353561 android.webview.ValueCallback except in the WebView glue layer
3562 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183563 """
3564 valuecallback_import_pattern = input_api.re.compile(
3565 r'^import android\.webkit\.ValueCallback;$')
3566
3567 errors = []
3568
3569 sources = lambda affected_file: input_api.FilterSourceFile(
3570 affected_file,
3571 black_list=(_EXCLUDED_PATHS +
3572 _TEST_CODE_EXCLUDED_PATHS +
3573 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353574 (r'^android_webview[\\/]glue[\\/].*',
3575 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493576 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183577
3578 for f in input_api.AffectedSourceFiles(sources):
3579 for line_num, line in f.ChangedContents():
3580 if valuecallback_import_pattern.search(line):
3581 errors.append("%s:%d" % (f.LocalPath(), line_num))
3582
3583 results = []
3584
3585 if errors:
3586 results.append(output_api.PresubmitError(
3587 'android.webkit.ValueCallback usage is detected outside of the glue'
3588 ' layer. To stay compatible with the support library, android.webkit.*'
3589 ' classes should only be used inside the glue layer and'
3590 ' org.chromium.base.Callback should be used instead.',
3591 errors))
3592
3593 return results
3594
3595
Becky Zhou7c69b50992018-12-10 19:37:573596def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3597 """Checks Android XML styles """
3598 import sys
3599 original_sys_path = sys.path
3600 try:
3601 sys.path = sys.path + [input_api.os_path.join(
3602 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3603 import checkxmlstyle
3604 finally:
3605 # Restore sys.path to what it was before.
3606 sys.path = original_sys_path
3607
3608 if is_check_on_upload:
3609 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3610 else:
3611 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3612
3613
agrievef32bcc72016-04-04 14:57:403614class PydepsChecker(object):
3615 def __init__(self, input_api, pydeps_files):
3616 self._file_cache = {}
3617 self._input_api = input_api
3618 self._pydeps_files = pydeps_files
3619
3620 def _LoadFile(self, path):
3621 """Returns the list of paths within a .pydeps file relative to //."""
3622 if path not in self._file_cache:
3623 with open(path) as f:
3624 self._file_cache[path] = f.read()
3625 return self._file_cache[path]
3626
3627 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3628 """Returns an interable of paths within the .pydep, relativized to //."""
3629 os_path = self._input_api.os_path
3630 pydeps_dir = os_path.dirname(pydeps_path)
3631 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3632 if not l.startswith('*'))
3633 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3634
3635 def _CreateFilesToPydepsMap(self):
3636 """Returns a map of local_path -> list_of_pydeps."""
3637 ret = {}
3638 for pydep_local_path in self._pydeps_files:
3639 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3640 ret.setdefault(path, []).append(pydep_local_path)
3641 return ret
3642
3643 def ComputeAffectedPydeps(self):
3644 """Returns an iterable of .pydeps files that might need regenerating."""
3645 affected_pydeps = set()
3646 file_to_pydeps_map = None
3647 for f in self._input_api.AffectedFiles(include_deletes=True):
3648 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463649 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3650 # subrepositories. We can't figure out which files change, so re-check
3651 # all files.
3652 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383653 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3654 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403655 return self._pydeps_files
3656 elif local_path.endswith('.pydeps'):
3657 if local_path in self._pydeps_files:
3658 affected_pydeps.add(local_path)
3659 elif local_path.endswith('.py'):
3660 if file_to_pydeps_map is None:
3661 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3662 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3663 return affected_pydeps
3664
3665 def DetermineIfStale(self, pydeps_path):
3666 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413667 import difflib
John Budorick47ca3fe2018-02-10 00:53:103668 import os
3669
agrievef32bcc72016-04-04 14:57:403670 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3671 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103672 env = dict(os.environ)
3673 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403674 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103675 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413676 old_contents = old_pydeps_data[2:]
3677 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403678 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413679 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403680
3681
Tibor Goldschwendt360793f72019-06-25 18:23:493682def _ParseGclientArgs():
3683 args = {}
3684 with open('build/config/gclient_args.gni', 'r') as f:
3685 for line in f:
3686 line = line.strip()
3687 if not line or line.startswith('#'):
3688 continue
3689 attribute, value = line.split('=')
3690 args[attribute.strip()] = value.strip()
3691 return args
3692
3693
agrievef32bcc72016-04-04 14:57:403694def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3695 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403696 # This check is for Python dependency lists (.pydeps files), and involves
3697 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3698 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283699 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003700 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493701 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403702 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3703 results = []
3704 # First, check for new / deleted .pydeps.
3705 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033706 # Check whether we are running the presubmit check for a file in src.
3707 # f.LocalPath is relative to repo (src, or internal repo).
3708 # os_path.exists is relative to src repo.
3709 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3710 # to src and we can conclude that the pydeps is in src.
3711 if input_api.os_path.exists(f.LocalPath()):
3712 if f.LocalPath().endswith('.pydeps'):
3713 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3714 results.append(output_api.PresubmitError(
3715 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3716 'remove %s' % f.LocalPath()))
3717 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3718 results.append(output_api.PresubmitError(
3719 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3720 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403721
3722 if results:
3723 return results
3724
3725 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3726
3727 for pydep_path in checker.ComputeAffectedPydeps():
3728 try:
phajdan.jr0d9878552016-11-04 10:49:413729 result = checker.DetermineIfStale(pydep_path)
3730 if result:
3731 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403732 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413733 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3734 'To regenerate, run:\n\n %s' %
3735 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403736 except input_api.subprocess.CalledProcessError as error:
3737 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3738 long_text=error.output)]
3739
3740 return results
3741
3742
glidere61efad2015-02-18 17:39:433743def _CheckSingletonInHeaders(input_api, output_api):
3744 """Checks to make sure no header files have |Singleton<|."""
3745 def FileFilter(affected_file):
3746 # It's ok for base/memory/singleton.h to have |Singleton<|.
3747 black_list = (_EXCLUDED_PATHS +
3748 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043749 (r"^base[\\/]memory[\\/]singleton\.h$",
3750 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473751 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433752 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3753
sergeyu34d21222015-09-16 00:11:443754 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433755 files = []
3756 for f in input_api.AffectedSourceFiles(FileFilter):
3757 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3758 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3759 contents = input_api.ReadFile(f)
3760 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243761 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433762 pattern.search(line)):
3763 files.append(f)
3764 break
3765
3766 if files:
yolandyandaabc6d2016-04-18 18:29:393767 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443768 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433769 'Please move them to an appropriate source file so that the ' +
3770 'template gets instantiated in a single compilation unit.',
3771 files) ]
3772 return []
3773
3774
[email protected]fd20b902014-05-09 02:14:533775_DEPRECATED_CSS = [
3776 # Values
3777 ( "-webkit-box", "flex" ),
3778 ( "-webkit-inline-box", "inline-flex" ),
3779 ( "-webkit-flex", "flex" ),
3780 ( "-webkit-inline-flex", "inline-flex" ),
3781 ( "-webkit-min-content", "min-content" ),
3782 ( "-webkit-max-content", "max-content" ),
3783
3784 # Properties
3785 ( "-webkit-background-clip", "background-clip" ),
3786 ( "-webkit-background-origin", "background-origin" ),
3787 ( "-webkit-background-size", "background-size" ),
3788 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443789 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533790
3791 # Functions
3792 ( "-webkit-gradient", "gradient" ),
3793 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3794 ( "-webkit-linear-gradient", "linear-gradient" ),
3795 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3796 ( "-webkit-radial-gradient", "radial-gradient" ),
3797 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3798]
3799
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203800
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493801# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243802def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533803 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253804 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343805 documentation and iOS CSS for dom distiller
3806 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253807 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533808 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493809 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253810 black_list = (_EXCLUDED_PATHS +
3811 _TEST_CODE_EXCLUDED_PATHS +
3812 input_api.DEFAULT_BLACK_LIST +
3813 (r"^chrome/common/extensions/docs",
3814 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343815 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443816 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253817 r"^native_client_sdk"))
3818 file_filter = lambda f: input_api.FilterSourceFile(
3819 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533820 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3821 for line_num, line in fpath.ChangedContents():
3822 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023823 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533824 results.append(output_api.PresubmitError(
3825 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3826 (fpath.LocalPath(), line_num, deprecated_value, value)))
3827 return results
3828
mohan.reddyf21db962014-10-16 12:26:473829
rlanday6802cf632017-05-30 17:48:363830def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363831 bad_files = {}
3832 for f in input_api.AffectedFiles(include_deletes=False):
3833 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493834 not f.LocalPath().startswith('third_party/blink') and
3835 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363836 continue
3837
Daniel Bratell65b033262019-04-23 08:17:063838 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363839 continue
3840
Vaclav Brozekd5de76a2018-03-17 07:57:503841 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363842 if "#include" in line and "../" in line]
3843 if not relative_includes:
3844 continue
3845 bad_files[f.LocalPath()] = relative_includes
3846
3847 if not bad_files:
3848 return []
3849
3850 error_descriptions = []
3851 for file_path, bad_lines in bad_files.iteritems():
3852 error_description = file_path
3853 for line in bad_lines:
3854 error_description += '\n ' + line
3855 error_descriptions.append(error_description)
3856
3857 results = []
3858 results.append(output_api.PresubmitError(
3859 'You added one or more relative #include paths (including "../").\n'
3860 'These shouldn\'t be used because they can be used to include headers\n'
3861 'from code that\'s not correctly specified as a dependency in the\n'
3862 'relevant BUILD.gn file(s).',
3863 error_descriptions))
3864
3865 return results
3866
Takeshi Yoshinoe387aa32017-08-02 13:16:133867
Daniel Bratell65b033262019-04-23 08:17:063868def _CheckForCcIncludes(input_api, output_api):
3869 """Check that nobody tries to include a cc file. It's a relatively
3870 common error which results in duplicate symbols in object
3871 files. This may not always break the build until someone later gets
3872 very confusing linking errors."""
3873 results = []
3874 for f in input_api.AffectedFiles(include_deletes=False):
3875 # We let third_party code do whatever it wants
3876 if (f.LocalPath().startswith('third_party') and
3877 not f.LocalPath().startswith('third_party/blink') and
3878 not f.LocalPath().startswith('third_party\\blink')):
3879 continue
3880
3881 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3882 continue
3883
3884 for _, line in f.ChangedContents():
3885 if line.startswith('#include "'):
3886 included_file = line.split('"')[1]
3887 if _IsCPlusPlusFile(input_api, included_file):
3888 # The most common naming for external files with C++ code,
3889 # apart from standard headers, is to call them foo.inc, but
3890 # Chromium sometimes uses foo-inc.cc so allow that as well.
3891 if not included_file.endswith(('.h', '-inc.cc')):
3892 results.append(output_api.PresubmitError(
3893 'Only header files or .inc files should be included in other\n'
3894 'C++ files. Compiling the contents of a cc file more than once\n'
3895 'will cause duplicate information in the build which may later\n'
3896 'result in strange link_errors.\n' +
3897 f.LocalPath() + ':\n ' +
3898 line))
3899
3900 return results
3901
3902
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203903def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3904 if not isinstance(key, ast.Str):
3905 return 'Key at line %d must be a string literal' % key.lineno
3906 if not isinstance(value, ast.Dict):
3907 return 'Value at line %d must be a dict' % value.lineno
3908 if len(value.keys) != 1:
3909 return 'Dict at line %d must have single entry' % value.lineno
3910 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3911 return (
3912 'Entry at line %d must have a string literal \'filepath\' as key' %
3913 value.lineno)
3914 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133915
Takeshi Yoshinoe387aa32017-08-02 13:16:133916
Sergey Ulanov4af16052018-11-08 02:41:463917def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203918 if not isinstance(key, ast.Str):
3919 return 'Key at line %d must be a string literal' % key.lineno
3920 if not isinstance(value, ast.List):
3921 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463922 for element in value.elts:
3923 if not isinstance(element, ast.Str):
3924 return 'Watchlist elements on line %d is not a string' % key.lineno
3925 if not email_regex.match(element.s):
3926 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3927 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133929
Takeshi Yoshinoe387aa32017-08-02 13:16:133930
Sergey Ulanov4af16052018-11-08 02:41:463931def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203932 mismatch_template = (
3933 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3934 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133935
Sergey Ulanov4af16052018-11-08 02:41:463936 email_regex = input_api.re.compile(
3937 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3938
3939 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203940 i = 0
3941 last_key = ''
3942 while True:
3943 if i >= len(wd_dict.keys):
3944 if i >= len(w_dict.keys):
3945 return None
3946 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3947 elif i >= len(w_dict.keys):
3948 return (
3949 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133950
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203951 wd_key = wd_dict.keys[i]
3952 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133953
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203954 result = _CheckWatchlistDefinitionsEntrySyntax(
3955 wd_key, wd_dict.values[i], ast)
3956 if result is not None:
3957 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133958
Sergey Ulanov4af16052018-11-08 02:41:463959 result = _CheckWatchlistsEntrySyntax(
3960 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203961 if result is not None:
3962 return 'Bad entry in WATCHLISTS dict: %s' % result
3963
3964 if wd_key.s != w_key.s:
3965 return mismatch_template % (
3966 '%s at line %d' % (wd_key.s, wd_key.lineno),
3967 '%s at line %d' % (w_key.s, w_key.lineno))
3968
3969 if wd_key.s < last_key:
3970 return (
3971 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3972 (wd_key.lineno, w_key.lineno))
3973 last_key = wd_key.s
3974
3975 i = i + 1
3976
3977
Sergey Ulanov4af16052018-11-08 02:41:463978def _CheckWATCHLISTSSyntax(expression, input_api):
3979 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203980 if not isinstance(expression, ast.Expression):
3981 return 'WATCHLISTS file must contain a valid expression'
3982 dictionary = expression.body
3983 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3984 return 'WATCHLISTS file must have single dict with exactly two entries'
3985
3986 first_key = dictionary.keys[0]
3987 first_value = dictionary.values[0]
3988 second_key = dictionary.keys[1]
3989 second_value = dictionary.values[1]
3990
3991 if (not isinstance(first_key, ast.Str) or
3992 first_key.s != 'WATCHLIST_DEFINITIONS' or
3993 not isinstance(first_value, ast.Dict)):
3994 return (
3995 'The first entry of the dict in WATCHLISTS file must be '
3996 'WATCHLIST_DEFINITIONS dict')
3997
3998 if (not isinstance(second_key, ast.Str) or
3999 second_key.s != 'WATCHLISTS' or
4000 not isinstance(second_value, ast.Dict)):
4001 return (
4002 'The second entry of the dict in WATCHLISTS file must be '
4003 'WATCHLISTS dict')
4004
Sergey Ulanov4af16052018-11-08 02:41:464005 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134006
4007
4008def _CheckWATCHLISTS(input_api, output_api):
4009 for f in input_api.AffectedFiles(include_deletes=False):
4010 if f.LocalPath() == 'WATCHLISTS':
4011 contents = input_api.ReadFile(f, 'r')
4012
4013 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204014 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134015 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204016 # Get an AST tree for it and scan the tree for detailed style checking.
4017 expression = input_api.ast.parse(
4018 contents, filename='WATCHLISTS', mode='eval')
4019 except ValueError as e:
4020 return [output_api.PresubmitError(
4021 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4022 except SyntaxError as e:
4023 return [output_api.PresubmitError(
4024 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4025 except TypeError as e:
4026 return [output_api.PresubmitError(
4027 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134028
Sergey Ulanov4af16052018-11-08 02:41:464029 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204030 if result is not None:
4031 return [output_api.PresubmitError(result)]
4032 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134033
4034 return []
4035
4036
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194037def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4038 """Checks that newly added header files have corresponding GN changes.
4039 Note that this is only a heuristic. To be precise, run script:
4040 build/check_gn_headers.py.
4041 """
4042
4043 def headers(f):
4044 return input_api.FilterSourceFile(
4045 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4046
4047 new_headers = []
4048 for f in input_api.AffectedSourceFiles(headers):
4049 if f.Action() != 'A':
4050 continue
4051 new_headers.append(f.LocalPath())
4052
4053 def gn_files(f):
4054 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4055
4056 all_gn_changed_contents = ''
4057 for f in input_api.AffectedSourceFiles(gn_files):
4058 for _, line in f.ChangedContents():
4059 all_gn_changed_contents += line
4060
4061 problems = []
4062 for header in new_headers:
4063 basename = input_api.os_path.basename(header)
4064 if basename not in all_gn_changed_contents:
4065 problems.append(header)
4066
4067 if problems:
4068 return [output_api.PresubmitPromptWarning(
4069 'Missing GN changes for new header files', items=sorted(problems),
4070 long_text='Please double check whether newly added header files need '
4071 'corresponding changes in gn or gni files.\nThis checking is only a '
4072 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4073 'Read https://crbug.com/661774 for more info.')]
4074 return []
4075
4076
Michael Giuffridad3bc8672018-10-25 22:48:024077def _CheckCorrectProductNameInMessages(input_api, output_api):
4078 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4079
4080 This assumes we won't intentionally reference one product from the other
4081 product.
4082 """
4083 all_problems = []
4084 test_cases = [{
4085 "filename_postfix": "google_chrome_strings.grd",
4086 "correct_name": "Chrome",
4087 "incorrect_name": "Chromium",
4088 }, {
4089 "filename_postfix": "chromium_strings.grd",
4090 "correct_name": "Chromium",
4091 "incorrect_name": "Chrome",
4092 }]
4093
4094 for test_case in test_cases:
4095 problems = []
4096 filename_filter = lambda x: x.LocalPath().endswith(
4097 test_case["filename_postfix"])
4098
4099 # Check each new line. Can yield false positives in multiline comments, but
4100 # easier than trying to parse the XML because messages can have nested
4101 # children, and associating message elements with affected lines is hard.
4102 for f in input_api.AffectedSourceFiles(filename_filter):
4103 for line_num, line in f.ChangedContents():
4104 if "<message" in line or "<!--" in line or "-->" in line:
4105 continue
4106 if test_case["incorrect_name"] in line:
4107 problems.append(
4108 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4109
4110 if problems:
4111 message = (
4112 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4113 % (test_case["correct_name"], test_case["correct_name"],
4114 test_case["incorrect_name"]))
4115 all_problems.append(
4116 output_api.PresubmitPromptWarning(message, items=problems))
4117
4118 return all_problems
4119
4120
Dirk Pranke3c18a382019-03-15 01:07:514121def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4122 # TODO(crbug.com/941824): We need to make sure the entries in
4123 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4124 # so that users of //buildtools in other projects get the same tooling
4125 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4126 # support to gclient, we can eliminate the duplication and delete
4127 # this presubmit check.
4128
4129 # Update this regexp if new revisions are added to the files.
4130 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264131 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514132
4133 # If a user is changing one revision, they need to change the same
4134 # line in both files. This means that any given change should contain
4135 # exactly the same list of changed lines that match the regexps. The
4136 # replace(' ', '') call allows us to ignore whitespace changes to the
4137 # lines. The 'long_text' parameter to the error will contain the
4138 # list of changed lines in both files, which should make it easy enough
4139 # to spot the error without going overboard in this implementation.
4140 revs_changes = {
4141 'DEPS': {},
4142 'buildtools/DEPS': {},
4143 }
4144 long_text = ''
4145
4146 for f in input_api.AffectedFiles(
4147 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4148 for line_num, line in f.ChangedContents():
4149 if rev_regexp.search(line):
4150 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4151 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4152
4153 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4154 return [output_api.PresubmitError(
4155 'Change buildtools revisions in sync in both //DEPS and '
4156 '//buildtools/DEPS.', long_text=long_text + '\n')]
4157 else:
4158 return []
4159
4160
Daniel Bratell93eb6c62019-04-29 20:13:364161def _CheckForTooLargeFiles(input_api, output_api):
4162 """Avoid large files, especially binary files, in the repository since
4163 git doesn't scale well for those. They will be in everyone's repo
4164 clones forever, forever making Chromium slower to clone and work
4165 with."""
4166
4167 # Uploading files to cloud storage is not trivial so we don't want
4168 # to set the limit too low, but the upper limit for "normal" large
4169 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4170 # anything over 20 MB is exceptional.
4171 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4172
4173 too_large_files = []
4174 for f in input_api.AffectedFiles():
4175 # Check both added and modified files (but not deleted files).
4176 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384177 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364178 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4179 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4180
4181 if too_large_files:
4182 message = (
4183 'Do not commit large files to git since git scales badly for those.\n' +
4184 'Instead put the large files in cloud storage and use DEPS to\n' +
4185 'fetch them.\n' + '\n'.join(too_large_files)
4186 )
4187 return [output_api.PresubmitError(
4188 'Too large files found in commit', long_text=message + '\n')]
4189 else:
4190 return []
4191
Max Morozb47503b2019-08-08 21:03:274192
4193def _CheckFuzzTargets(input_api, output_api):
4194 """Checks specific for fuzz target sources."""
4195 EXPORTED_SYMBOLS = [
4196 'LLVMFuzzerInitialize',
4197 'LLVMFuzzerCustomMutator',
4198 'LLVMFuzzerCustomCrossOver',
4199 'LLVMFuzzerMutate',
4200 ]
4201
4202 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4203
4204 def FilterFile(affected_file):
4205 """Ignore libFuzzer source code."""
4206 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4207 black_list = r"^third_party[\\/]libFuzzer"
4208
4209 return input_api.FilterSourceFile(
4210 affected_file,
4211 white_list=[white_list],
4212 black_list=[black_list])
4213
4214 files_with_missing_header = []
4215 for f in input_api.AffectedSourceFiles(FilterFile):
4216 contents = input_api.ReadFile(f, 'r')
4217 if REQUIRED_HEADER in contents:
4218 continue
4219
4220 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4221 files_with_missing_header.append(f.LocalPath())
4222
4223 if not files_with_missing_header:
4224 return []
4225
4226 long_text = (
4227 'If you define any of the libFuzzer optional functions (%s), it is '
4228 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4229 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4230 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4231 'to access command line arguments passed to the fuzzer. Instead, prefer '
4232 'static initialization and shared resources as documented in '
4233 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4234 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4235 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4236 )
4237
4238 return [output_api.PresubmitPromptWarning(
4239 message="Missing '%s' in:" % REQUIRED_HEADER,
4240 items=files_with_missing_header,
4241 long_text=long_text)]
4242
4243
Mohamed Heikald048240a2019-11-12 16:57:374244def _CheckNewImagesWarning(input_api, output_api):
4245 """
4246 Warns authors who add images into the repo to make sure their images are
4247 optimized before committing.
4248 """
4249 images_added = False
4250 image_paths = []
4251 errors = []
4252 filter_lambda = lambda x: input_api.FilterSourceFile(
4253 x,
4254 black_list=(('(?i).*test', r'.*\/junit\/')
4255 + input_api.DEFAULT_BLACK_LIST),
4256 white_list=[r'.*\/(drawable|mipmap)' ]
4257 )
4258 for f in input_api.AffectedFiles(
4259 include_deletes=False, file_filter=filter_lambda):
4260 local_path = f.LocalPath().lower()
4261 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4262 images_added = True
4263 image_paths.append(f)
4264 if images_added:
4265 errors.append(output_api.PresubmitPromptWarning(
4266 'It looks like you are trying to commit some images. If these are '
4267 'non-test-only images, please make sure to read and apply the tips in '
4268 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4269 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4270 'FYI only and will not block your CL on the CQ.', image_paths))
4271 return errors
4272
4273
dgnaa68d5e2015-06-10 10:08:224274def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574275 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224276 results = []
dgnaa68d5e2015-06-10 10:08:224277 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174278 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224279 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294280 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064281 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4282 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424283 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184284 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574285 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374286 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154287 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574288 return results
4289
4290def _AndroidSpecificOnCommitChecks(input_api, output_api):
4291 """Groups commit checks that target android code."""
4292 results = []
4293 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224294 return results
4295
Chris Hall59f8d0c72020-05-01 07:31:194296# TODO(chrishall): could we additionally match on any path owned by
4297# ui/accessibility/OWNERS ?
4298_ACCESSIBILITY_PATHS = (
4299 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4300 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4301 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4302 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4303 r"^content[\\/]browser[\\/]accessibility[\\/]",
4304 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4305 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4306 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4307 r"^ui[\\/]accessibility[\\/]",
4308 r"^ui[\\/]views[\\/]accessibility[\\/]",
4309)
4310
4311def _CheckAccessibilityRelnotesField(input_api, output_api):
4312 """Checks that commits to accessibility code contain an AX-Relnotes field in
4313 their commit message."""
4314 def FileFilter(affected_file):
4315 paths = _ACCESSIBILITY_PATHS
4316 return input_api.FilterSourceFile(affected_file, white_list=paths)
4317
4318 # Only consider changes affecting accessibility paths.
4319 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4320 return []
4321
Akihiro Ota08108e542020-05-20 15:30:534322 # AX-Relnotes can appear in either the description or the footer.
4323 # When searching the description, require 'AX-Relnotes:' to appear at the
4324 # beginning of a line.
4325 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4326 description_has_relnotes = any(ax_regex.match(line)
4327 for line in input_api.change.DescriptionText().lower().splitlines())
4328
4329 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4330 'AX-Relnotes', [])
4331 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194332 return []
4333
4334 # TODO(chrishall): link to Relnotes documentation in message.
4335 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4336 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4337 "user-facing changes"
4338 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4339 "user-facing effects"
4340 "\n if this is confusing or annoying then please contact members "
4341 "of ui/accessibility/OWNERS.")
4342
4343 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224344
[email protected]22c9bd72011-03-27 16:47:394345def _CommonChecks(input_api, output_api):
4346 """Checks common to both upload and commit."""
4347 results = []
4348 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384349 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544350 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084351
4352 author = input_api.change.author_email
4353 if author and author not in _KNOWN_ROBOTS:
4354 results.extend(
4355 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4356
Chris Hall59f8d0c72020-05-01 07:31:194357 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194358 results.extend(
[email protected]760deea2013-12-10 19:33:494359 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234360 results.extend(
4361 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544362 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184363 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344364 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524365 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224366 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444367 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594368 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314369 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064370 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124371 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184372 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224373 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304374 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494375 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034376 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494377 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444378 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294379 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274380 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074381 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544382 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444383 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394384 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554385 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044386 results.extend(
4387 input_api.canned_checks.CheckChangeHasNoTabs(
4388 input_api,
4389 output_api,
4390 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404391 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164392 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084393 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244394 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474395 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044396 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054397 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144398 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234399 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434400 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404401 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154402 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034403 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134404 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264405 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504406 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364407 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064408 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134409 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434410 results.extend(input_api.RunTests(
4411 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264412 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124413 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024414 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514415 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364416 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004417 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514418 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244419
Vaclav Brozekcdc7defb2018-03-20 09:54:354420 for f in input_api.AffectedFiles():
4421 path, name = input_api.os_path.split(f.LocalPath())
4422 if name == 'PRESUBMIT.py':
4423 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004424 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4425 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074426 # The PRESUBMIT.py file (and the directory containing it) might
4427 # have been affected by being moved or removed, so only try to
4428 # run the tests if they still exist.
4429 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4430 input_api, output_api, full_path,
4431 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394432 return results
[email protected]1f7b4172010-01-28 01:17:344433
[email protected]b337cb5b2011-01-23 21:24:054434
[email protected]b8079ae4a2012-12-05 19:56:494435def _CheckPatchFiles(input_api, output_api):
4436 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4437 if f.LocalPath().endswith(('.orig', '.rej'))]
4438 if problems:
4439 return [output_api.PresubmitError(
4440 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034441 else:
4442 return []
[email protected]b8079ae4a2012-12-05 19:56:494443
4444
Kent Tamura5a8755d2017-06-29 23:37:074445def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214446 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4447 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4448 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074449 include_re = input_api.re.compile(
4450 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4451 extension_re = input_api.re.compile(r'\.[a-z]+$')
4452 errors = []
4453 for f in input_api.AffectedFiles():
4454 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4455 continue
4456 found_line_number = None
4457 found_macro = None
4458 for line_num, line in f.ChangedContents():
4459 match = macro_re.search(line)
4460 if match:
4461 found_line_number = line_num
4462 found_macro = match.group(2)
4463 break
4464 if not found_line_number:
4465 continue
4466
4467 found_include = False
4468 for line in f.NewContents():
4469 if include_re.search(line):
4470 found_include = True
4471 break
4472 if found_include:
4473 continue
4474
4475 if not f.LocalPath().endswith('.h'):
4476 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4477 try:
4478 content = input_api.ReadFile(primary_header_path, 'r')
4479 if include_re.search(content):
4480 continue
4481 except IOError:
4482 pass
4483 errors.append('%s:%d %s macro is used without including build/'
4484 'build_config.h.'
4485 % (f.LocalPath(), found_line_number, found_macro))
4486 if errors:
4487 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4488 return []
4489
4490
[email protected]b00342e7f2013-03-26 16:21:544491def _DidYouMeanOSMacro(bad_macro):
4492 try:
4493 return {'A': 'OS_ANDROID',
4494 'B': 'OS_BSD',
4495 'C': 'OS_CHROMEOS',
4496 'F': 'OS_FREEBSD',
4497 'L': 'OS_LINUX',
4498 'M': 'OS_MACOSX',
4499 'N': 'OS_NACL',
4500 'O': 'OS_OPENBSD',
4501 'P': 'OS_POSIX',
4502 'S': 'OS_SOLARIS',
4503 'W': 'OS_WIN'}[bad_macro[3].upper()]
4504 except KeyError:
4505 return ''
4506
4507
4508def _CheckForInvalidOSMacrosInFile(input_api, f):
4509 """Check for sensible looking, totally invalid OS macros."""
4510 preprocessor_statement = input_api.re.compile(r'^\s*#')
4511 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4512 results = []
4513 for lnum, line in f.ChangedContents():
4514 if preprocessor_statement.search(line):
4515 for match in os_macro.finditer(line):
4516 if not match.group(1) in _VALID_OS_MACROS:
4517 good = _DidYouMeanOSMacro(match.group(1))
4518 did_you_mean = ' (did you mean %s?)' % good if good else ''
4519 results.append(' %s:%d %s%s' % (f.LocalPath(),
4520 lnum,
4521 match.group(1),
4522 did_you_mean))
4523 return results
4524
4525
4526def _CheckForInvalidOSMacros(input_api, output_api):
4527 """Check all affected files for invalid OS macros."""
4528 bad_macros = []
tzik3f295992018-12-04 20:32:234529 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474530 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544531 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4532
4533 if not bad_macros:
4534 return []
4535
4536 return [output_api.PresubmitError(
4537 'Possibly invalid OS macro[s] found. Please fix your code\n'
4538 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4539
lliabraa35bab3932014-10-01 12:16:444540
4541def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4542 """Check all affected files for invalid "if defined" macros."""
4543 ALWAYS_DEFINED_MACROS = (
4544 "TARGET_CPU_PPC",
4545 "TARGET_CPU_PPC64",
4546 "TARGET_CPU_68K",
4547 "TARGET_CPU_X86",
4548 "TARGET_CPU_ARM",
4549 "TARGET_CPU_MIPS",
4550 "TARGET_CPU_SPARC",
4551 "TARGET_CPU_ALPHA",
4552 "TARGET_IPHONE_SIMULATOR",
4553 "TARGET_OS_EMBEDDED",
4554 "TARGET_OS_IPHONE",
4555 "TARGET_OS_MAC",
4556 "TARGET_OS_UNIX",
4557 "TARGET_OS_WIN32",
4558 )
4559 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4560 results = []
4561 for lnum, line in f.ChangedContents():
4562 for match in ifdef_macro.finditer(line):
4563 if match.group(1) in ALWAYS_DEFINED_MACROS:
4564 always_defined = ' %s is always defined. ' % match.group(1)
4565 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4566 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4567 lnum,
4568 always_defined,
4569 did_you_mean))
4570 return results
4571
4572
4573def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4574 """Check all affected files for invalid "if defined" macros."""
4575 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054576 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444577 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054578 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214579 continue
lliabraa35bab3932014-10-01 12:16:444580 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4581 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4582
4583 if not bad_macros:
4584 return []
4585
4586 return [output_api.PresubmitError(
4587 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4588 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4589 bad_macros)]
4590
4591
mlamouria82272622014-09-16 18:45:044592def _CheckForIPCRules(input_api, output_api):
4593 """Check for same IPC rules described in
4594 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4595 """
4596 base_pattern = r'IPC_ENUM_TRAITS\('
4597 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4598 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4599
4600 problems = []
4601 for f in input_api.AffectedSourceFiles(None):
4602 local_path = f.LocalPath()
4603 if not local_path.endswith('.h'):
4604 continue
4605 for line_number, line in f.ChangedContents():
4606 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4607 problems.append(
4608 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4609
4610 if problems:
4611 return [output_api.PresubmitPromptWarning(
4612 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4613 else:
4614 return []
4615
[email protected]b00342e7f2013-03-26 16:21:544616
Stephen Martinis97a394142018-06-07 23:06:054617def _CheckForLongPathnames(input_api, output_api):
4618 """Check to make sure no files being submitted have long paths.
4619 This causes issues on Windows.
4620 """
4621 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194622 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054623 local_path = f.LocalPath()
4624 # Windows has a path limit of 260 characters. Limit path length to 200 so
4625 # that we have some extra for the prefix on dev machines and the bots.
4626 if len(local_path) > 200:
4627 problems.append(local_path)
4628
4629 if problems:
4630 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4631 else:
4632 return []
4633
4634
Daniel Bratell8ba52722018-03-02 16:06:144635def _CheckForIncludeGuards(input_api, output_api):
4636 """Check that header files have proper guards against multiple inclusion.
4637 If a file should not have such guards (and it probably should) then it
4638 should include the string "no-include-guard-because-multiply-included".
4639 """
Daniel Bratell6a75baef62018-06-04 10:04:454640 def is_chromium_header_file(f):
4641 # We only check header files under the control of the Chromium
4642 # project. That is, those outside third_party apart from
4643 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324644 # We also exclude *_message_generator.h headers as they use
4645 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454646 file_with_path = input_api.os_path.normpath(f.LocalPath())
4647 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324648 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454649 (not file_with_path.startswith('third_party') or
4650 file_with_path.startswith(
4651 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144652
4653 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344654 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144655
4656 errors = []
4657
Daniel Bratell6a75baef62018-06-04 10:04:454658 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144659 guard_name = None
4660 guard_line_number = None
4661 seen_guard_end = False
4662
4663 file_with_path = input_api.os_path.normpath(f.LocalPath())
4664 base_file_name = input_api.os_path.splitext(
4665 input_api.os_path.basename(file_with_path))[0]
4666 upper_base_file_name = base_file_name.upper()
4667
4668 expected_guard = replace_special_with_underscore(
4669 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144670
4671 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574672 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4673 # are too many (1000+) files with slight deviations from the
4674 # coding style. The most important part is that the include guard
4675 # is there, and that it's unique, not the name so this check is
4676 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144677 #
4678 # As code becomes more uniform, this could be made stricter.
4679
4680 guard_name_pattern_list = [
4681 # Anything with the right suffix (maybe with an extra _).
4682 r'\w+_H__?',
4683
Daniel Bratell39b5b062018-05-16 18:09:574684 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144685 r'\w+_h',
4686
4687 # Anything including the uppercase name of the file.
4688 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4689 upper_base_file_name)) + r'\w*',
4690 ]
4691 guard_name_pattern = '|'.join(guard_name_pattern_list)
4692 guard_pattern = input_api.re.compile(
4693 r'#ifndef\s+(' + guard_name_pattern + ')')
4694
4695 for line_number, line in enumerate(f.NewContents()):
4696 if 'no-include-guard-because-multiply-included' in line:
4697 guard_name = 'DUMMY' # To not trigger check outside the loop.
4698 break
4699
4700 if guard_name is None:
4701 match = guard_pattern.match(line)
4702 if match:
4703 guard_name = match.group(1)
4704 guard_line_number = line_number
4705
Daniel Bratell39b5b062018-05-16 18:09:574706 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454707 # don't match the chromium style guide, but new files should
4708 # get it right.
4709 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574710 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144711 errors.append(output_api.PresubmitPromptWarning(
4712 'Header using the wrong include guard name %s' % guard_name,
4713 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574714 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144715 else:
4716 # The line after #ifndef should have a #define of the same name.
4717 if line_number == guard_line_number + 1:
4718 expected_line = '#define %s' % guard_name
4719 if line != expected_line:
4720 errors.append(output_api.PresubmitPromptWarning(
4721 'Missing "%s" for include guard' % expected_line,
4722 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4723 'Expected: %r\nGot: %r' % (expected_line, line)))
4724
4725 if not seen_guard_end and line == '#endif // %s' % guard_name:
4726 seen_guard_end = True
4727 elif seen_guard_end:
4728 if line.strip() != '':
4729 errors.append(output_api.PresubmitPromptWarning(
4730 'Include guard %s not covering the whole file' % (
4731 guard_name), [f.LocalPath()]))
4732 break # Nothing else to check and enough to warn once.
4733
4734 if guard_name is None:
4735 errors.append(output_api.PresubmitPromptWarning(
4736 'Missing include guard %s' % expected_guard,
4737 [f.LocalPath()],
4738 'Missing include guard in %s\n'
4739 'Recommended name: %s\n'
4740 'This check can be disabled by having the string\n'
4741 'no-include-guard-because-multiply-included in the header.' %
4742 (f.LocalPath(), expected_guard)))
4743
4744 return errors
4745
4746
mostynbb639aca52015-01-07 20:31:234747def _CheckForWindowsLineEndings(input_api, output_api):
4748 """Check source code and known ascii text files for Windows style line
4749 endings.
4750 """
earthdok1b5e0ee2015-03-10 15:19:104751 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234752
4753 file_inclusion_pattern = (
4754 known_text_files,
4755 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4756 )
4757
mostynbb639aca52015-01-07 20:31:234758 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534759 source_file_filter = lambda f: input_api.FilterSourceFile(
4760 f, white_list=file_inclusion_pattern, black_list=None)
4761 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504762 include_file = False
4763 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234764 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504765 include_file = True
4766 if include_file:
4767 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234768
4769 if problems:
4770 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4771 'these files to contain Windows style line endings?\n' +
4772 '\n'.join(problems))]
4773
4774 return []
4775
4776
Vaclav Brozekd5de76a2018-03-17 07:57:504777def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134778 """Checks that all source files use SYSLOG properly."""
4779 syslog_files = []
4780 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564781 for line_number, line in f.ChangedContents():
4782 if 'SYSLOG' in line:
4783 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4784
pastarmovj89f7ee12016-09-20 14:58:134785 if syslog_files:
4786 return [output_api.PresubmitPromptWarning(
4787 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4788 ' calls.\nFiles to check:\n', items=syslog_files)]
4789 return []
4790
4791
[email protected]1f7b4172010-01-28 01:17:344792def CheckChangeOnUpload(input_api, output_api):
4793 results = []
4794 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474795 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284796 results.extend(
jam93a6ee792017-02-08 23:59:224797 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194798 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224799 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134800 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164801 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534802 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194803 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274804 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544805 return results
[email protected]ca8d1982009-02-19 16:33:124806
4807
[email protected]1bfb8322014-04-23 01:02:414808def GetTryServerMasterForBot(bot):
4809 """Returns the Try Server master for the given bot.
4810
[email protected]0bb112362014-07-26 04:38:324811 It tries to guess the master from the bot name, but may still fail
4812 and return None. There is no longer a default master.
4813 """
4814 # Potentially ambiguous bot names are listed explicitly.
4815 master_map = {
tandriie5587792016-07-14 00:34:504816 'chromium_presubmit': 'master.tryserver.chromium.linux',
4817 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414818 }
[email protected]0bb112362014-07-26 04:38:324819 master = master_map.get(bot)
4820 if not master:
wnwen4fbaab82016-05-25 12:54:364821 if 'android' in bot:
tandriie5587792016-07-14 00:34:504822 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364823 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504824 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324825 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504826 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324827 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504828 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324829 return master
[email protected]1bfb8322014-04-23 01:02:414830
4831
[email protected]ca8d1982009-02-19 16:33:124832def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544833 results = []
[email protected]1f7b4172010-01-28 01:17:344834 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574835 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544836 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274837 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344838 input_api,
4839 output_api,
[email protected]2fdd1f362013-01-16 03:56:034840 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274841
jam93a6ee792017-02-08 23:59:224842 results.extend(
4843 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544844 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4845 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384846 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4847 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414848 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4849 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544850 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144851
4852
Rainhard Findlingfc31844c52020-05-15 09:58:264853def _CheckStrings(input_api, output_api):
4854 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024855 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4856 # footer is set to true.
4857 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264858 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024859 footer.lower()
4860 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264861 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024862
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144863 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264864 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144865 import sys
4866 from io import StringIO
4867
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144868 new_or_added_paths = set(f.LocalPath()
4869 for f in input_api.AffectedFiles()
4870 if (f.Action() == 'A' or f.Action() == 'M'))
4871 removed_paths = set(f.LocalPath()
4872 for f in input_api.AffectedFiles(include_deletes=True)
4873 if f.Action() == 'D')
4874
4875 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264876 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164877 if not affected_grds:
4878 return []
4879
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144880 affected_png_paths = [f.AbsoluteLocalPath()
4881 for f in input_api.AffectedFiles()
4882 if (f.LocalPath().endswith('.png'))]
4883
4884 # Check for screenshots. Developers can upload screenshots using
4885 # tools/translation/upload_screenshots.py which finds and uploads
4886 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4887 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4888 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4889 #
4890 # The logic here is as follows:
4891 #
4892 # - If the CL has a .png file under the screenshots directory for a grd
4893 # file, warn the developer. Actual images should never be checked into the
4894 # Chrome repo.
4895 #
4896 # - If the CL contains modified or new messages in grd files and doesn't
4897 # contain the corresponding .sha1 files, warn the developer to add images
4898 # and upload them via tools/translation/upload_screenshots.py.
4899 #
4900 # - If the CL contains modified or new messages in grd files and the
4901 # corresponding .sha1 files, everything looks good.
4902 #
4903 # - If the CL contains removed messages in grd files but the corresponding
4904 # .sha1 files aren't removed, warn the developer to remove them.
4905 unnecessary_screenshots = []
4906 missing_sha1 = []
4907 unnecessary_sha1_files = []
4908
Rainhard Findlingfc31844c52020-05-15 09:58:264909 # This checks verifies that the ICU syntax of messages this CL touched is
4910 # valid, and reports any found syntax errors.
4911 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4912 # without developers being aware of them. Later on, such ICU syntax errors
4913 # break message extraction for translation, hence would block Chromium
4914 # translations until they are fixed.
4915 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144916
4917 def _CheckScreenshotAdded(screenshots_dir, message_id):
4918 sha1_path = input_api.os_path.join(
4919 screenshots_dir, message_id + '.png.sha1')
4920 if sha1_path not in new_or_added_paths:
4921 missing_sha1.append(sha1_path)
4922
4923
4924 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4925 sha1_path = input_api.os_path.join(
4926 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034927 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144928 unnecessary_sha1_files.append(sha1_path)
4929
Rainhard Findlingfc31844c52020-05-15 09:58:264930
4931 def _ValidateIcuSyntax(text, level, signatures):
4932 """Validates ICU syntax of a text string.
4933
4934 Check if text looks similar to ICU and checks for ICU syntax correctness
4935 in this case. Reports various issues with ICU syntax and values of
4936 variants. Supports checking of nested messages. Accumulate information of
4937 each ICU messages found in the text for further checking.
4938
4939 Args:
4940 text: a string to check.
4941 level: a number of current nesting level.
4942 signatures: an accumulator, a list of tuple of (level, variable,
4943 kind, variants).
4944
4945 Returns:
4946 None if a string is not ICU or no issue detected.
4947 A tuple of (message, start index, end index) if an issue detected.
4948 """
4949 valid_types = {
4950 'plural': (frozenset(
4951 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4952 frozenset(['=1', 'other'])),
4953 'selectordinal': (frozenset(
4954 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4955 frozenset(['one', 'other'])),
4956 'select': (frozenset(), frozenset(['other'])),
4957 }
4958
4959 # Check if the message looks like an attempt to use ICU
4960 # plural. If yes - check if its syntax strictly matches ICU format.
4961 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4962 if not like:
4963 signatures.append((level, None, None, None))
4964 return
4965
4966 # Check for valid prefix and suffix
4967 m = re.match(
4968 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4969 r'(plural|selectordinal|select),\s*'
4970 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4971 if not m:
4972 return (('This message looks like an ICU plural, '
4973 'but does not follow ICU syntax.'), like.start(), like.end())
4974 starting, variable, kind, variant_pairs = m.groups()
4975 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4976 if depth:
4977 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4978 len(text))
4979 first = text[0]
4980 ending = text[last_pos:]
4981 if not starting:
4982 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4983 last_pos)
4984 if not ending or '}' not in ending:
4985 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4986 last_pos)
4987 elif first != '{':
4988 return (
4989 ('Invalid ICU format. Extra characters at the start of a complex '
4990 'message (go/icu-message-migration): "%s"') %
4991 starting, 0, len(starting))
4992 elif ending != '}':
4993 return (('Invalid ICU format. Extra characters at the end of a complex '
4994 'message (go/icu-message-migration): "%s"')
4995 % ending, last_pos - 1, len(text) - 1)
4996 if kind not in valid_types:
4997 return (('Unknown ICU message type %s. '
4998 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4999 known, required = valid_types[kind]
5000 defined_variants = set()
5001 for variant, variant_range, value, value_range in variants:
5002 start, end = variant_range
5003 if variant in defined_variants:
5004 return ('Variant "%s" is defined more than once' % variant,
5005 start, end)
5006 elif known and variant not in known:
5007 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5008 start, end)
5009 defined_variants.add(variant)
5010 # Check for nested structure
5011 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5012 if res:
5013 return (res[0], res[1] + value_range[0] + 1,
5014 res[2] + value_range[0] + 1)
5015 missing = required - defined_variants
5016 if missing:
5017 return ('Required variants missing: %s' % ', '.join(missing), 0,
5018 len(text))
5019 signatures.append((level, variable, kind, defined_variants))
5020
5021
5022 def _ParseIcuVariants(text, offset=0):
5023 """Parse variants part of ICU complex message.
5024
5025 Builds a tuple of variant names and values, as well as
5026 their offsets in the input string.
5027
5028 Args:
5029 text: a string to parse
5030 offset: additional offset to add to positions in the text to get correct
5031 position in the complete ICU string.
5032
5033 Returns:
5034 List of tuples, each tuple consist of four fields: variant name,
5035 variant name span (tuple of two integers), variant value, value
5036 span (tuple of two integers).
5037 """
5038 depth, start, end = 0, -1, -1
5039 variants = []
5040 key = None
5041 for idx, char in enumerate(text):
5042 if char == '{':
5043 if not depth:
5044 start = idx
5045 chunk = text[end + 1:start]
5046 key = chunk.strip()
5047 pos = offset + end + 1 + chunk.find(key)
5048 span = (pos, pos + len(key))
5049 depth += 1
5050 elif char == '}':
5051 if not depth:
5052 return variants, depth, offset + idx
5053 depth -= 1
5054 if not depth:
5055 end = idx
5056 variants.append((key, span, text[start:end + 1], (offset + start,
5057 offset + end + 1)))
5058 return variants, depth, offset + end + 1
5059
meacer8c0d3832019-12-26 21:46:165060 try:
5061 old_sys_path = sys.path
5062 sys.path = sys.path + [input_api.os_path.join(
5063 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5064 from helper import grd_helper
5065 finally:
5066 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145067
5068 for f in affected_grds:
5069 file_path = f.LocalPath()
5070 old_id_to_msg_map = {}
5071 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385072 # Note that this code doesn't check if the file has been deleted. This is
5073 # OK because it only uses the old and new file contents and doesn't load
5074 # the file via its path.
5075 # It's also possible that a file's content refers to a renamed or deleted
5076 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5077 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5078 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079 if file_path.endswith('.grdp'):
5080 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585081 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395082 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145083 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585084 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395085 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145086 else:
meacerff8a9b62019-12-10 19:43:585087 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145088 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585089 old_id_to_msg_map = grd_helper.GetGrdMessages(
5090 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145091 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585092 new_id_to_msg_map = grd_helper.GetGrdMessages(
5093 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145094
5095 # Compute added, removed and modified message IDs.
5096 old_ids = set(old_id_to_msg_map)
5097 new_ids = set(new_id_to_msg_map)
5098 added_ids = new_ids - old_ids
5099 removed_ids = old_ids - new_ids
5100 modified_ids = set([])
5101 for key in old_ids.intersection(new_ids):
5102 if (old_id_to_msg_map[key].FormatXml()
5103 != new_id_to_msg_map[key].FormatXml()):
5104 modified_ids.add(key)
5105
5106 grd_name, ext = input_api.os_path.splitext(
5107 input_api.os_path.basename(file_path))
5108 screenshots_dir = input_api.os_path.join(
5109 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5110
Rainhard Findlingfc31844c52020-05-15 09:58:265111 if run_screenshot_check:
5112 # Check the screenshot directory for .png files. Warn if there is any.
5113 for png_path in affected_png_paths:
5114 if png_path.startswith(screenshots_dir):
5115 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145116
Rainhard Findlingfc31844c52020-05-15 09:58:265117 for added_id in added_ids:
5118 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
Rainhard Findlingfc31844c52020-05-15 09:58:265120 for modified_id in modified_ids:
5121 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122
Rainhard Findlingfc31844c52020-05-15 09:58:265123 for removed_id in removed_ids:
5124 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5125
5126 # Check new and changed strings for ICU syntax errors.
5127 for key in added_ids.union(modified_ids):
5128 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5129 err = _ValidateIcuSyntax(msg, 0, [])
5130 if err is not None:
5131 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132
5133 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265134 if run_screenshot_check:
5135 if unnecessary_screenshots:
5136 results.append(output_api.PresubmitNotifyResult(
5137 'Do not include actual screenshots in the changelist. Run '
5138 'tools/translate/upload_screenshots.py to upload them instead:',
5139 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
Rainhard Findlingfc31844c52020-05-15 09:58:265141 if missing_sha1:
5142 results.append(output_api.PresubmitNotifyResult(
5143 'You are adding or modifying UI strings.\n'
5144 'To ensure the best translations, take screenshots of the relevant UI '
5145 '(https://g.co/chrome/translation) and add these files to your '
5146 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145147
Rainhard Findlingfc31844c52020-05-15 09:58:265148 if unnecessary_sha1_files:
5149 results.append(output_api.PresubmitNotifyResult(
5150 'You removed strings associated with these files. Remove:',
5151 sorted(unnecessary_sha1_files)))
5152 else:
5153 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5154 'screenshots check.'))
5155
5156 if icu_syntax_errors:
5157 results.append(output_api.PresubmitError(
5158 'ICU syntax errors were found in the following strings (problems or '
5159 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145160
5161 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125162
5163
5164def _CheckTranslationExpectations(input_api, output_api,
5165 repo_root=None,
5166 translation_expectations_path=None,
5167 grd_files=None):
5168 import sys
5169 affected_grds = [f for f in input_api.AffectedFiles()
5170 if (f.LocalPath().endswith('.grd') or
5171 f.LocalPath().endswith('.grdp'))]
5172 if not affected_grds:
5173 return []
5174
5175 try:
5176 old_sys_path = sys.path
5177 sys.path = sys.path + [
5178 input_api.os_path.join(
5179 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5180 from helper import git_helper
5181 from helper import translation_helper
5182 finally:
5183 sys.path = old_sys_path
5184
5185 # Check that translation expectations can be parsed and we can get a list of
5186 # translatable grd files. |repo_root| and |translation_expectations_path| are
5187 # only passed by tests.
5188 if not repo_root:
5189 repo_root = input_api.PresubmitLocalPath()
5190 if not translation_expectations_path:
5191 translation_expectations_path = input_api.os_path.join(
5192 repo_root, 'tools', 'gritsettings',
5193 'translation_expectations.pyl')
5194 if not grd_files:
5195 grd_files = git_helper.list_grds_in_repository(repo_root)
5196
5197 try:
5198 translation_helper.get_translatable_grds(repo_root, grd_files,
5199 translation_expectations_path)
5200 except Exception as e:
5201 return [output_api.PresubmitNotifyResult(
5202 'Failed to get a list of translatable grd files. This happens when:\n'
5203 ' - One of the modified grd or grdp files cannot be parsed or\n'
5204 ' - %s is not updated.\n'
5205 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5206 return []
Ken Rockotc31f4832020-05-29 18:58:515207
5208
5209def _CheckStableMojomChanges(input_api, output_api):
5210 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095211 changed_mojoms = input_api.AffectedFiles(
5212 include_deletes=True,
5213 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515214 delta = []
5215 for mojom in changed_mojoms:
5216 old_contents = ''.join(mojom.OldContents()) or None
5217 new_contents = ''.join(mojom.NewContents()) or None
5218 delta.append({
5219 'filename': mojom.LocalPath(),
5220 'old': '\n'.join(mojom.OldContents()) or None,
5221 'new': '\n'.join(mojom.NewContents()) or None,
5222 })
5223
5224 process = input_api.subprocess.Popen(
5225 [input_api.python_executable,
5226 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5227 'public', 'tools', 'mojom',
5228 'check_stable_mojom_compatibility.py'),
5229 '--src-root', input_api.PresubmitLocalPath()],
5230 stdin=input_api.subprocess.PIPE,
5231 stdout=input_api.subprocess.PIPE,
5232 stderr=input_api.subprocess.PIPE,
5233 universal_newlines=True)
5234 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5235 if process.returncode:
5236 return [output_api.PresubmitError(
5237 'One or more [Stable] mojom definitions appears to have been changed '
5238 'in a way that is not backward-compatible.',
5239 long_text=error)]
5240 return []