blob: 6b6ca04c3648f1e97805889fef7adb54699f82ba [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.
danakj7a2b7082019-05-21 21:13:51286 '^chrome/browser/',
287 '^chrome/chrome_elf/',
danakj7a2b7082019-05-21 21:13:51288 '^chrome/installer/',
danakj7a2b7082019-05-21 21:13:51289 '^chrome/services/',
290 '^chrome/test/',
291 '^chrome/tools/',
292 '^chrome/utility/',
danakj7a2b7082019-05-21 21:13:51293 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51294 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51295 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51296 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51297 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51298 '^components/arc/',
299 '^components/assist_ranker/',
300 '^components/autofill/',
301 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51302 '^components/browser_watcher/',
danakj7a2b7082019-05-21 21:13:51303 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51304 '^components/chromeos_camera/',
305 '^components/component_updater/',
306 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51307 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51308 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36309 '^components/dom_distiller/',
danakj7a2b7082019-05-21 21:13:51310 '^components/drive/',
311 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51312 '^components/feedback/',
313 '^components/flags_ui/',
314 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51315 '^components/guest_view/',
316 '^components/heap_profiling/',
317 '^components/history/',
318 '^components/image_fetcher/',
319 '^components/invalidation/',
320 '^components/keyed_service/',
321 '^components/login/',
322 '^components/metrics/',
323 '^components/metrics_services_manager/',
324 '^components/nacl/',
325 '^components/navigation_interception/',
326 '^components/net_log/',
327 '^components/network_time/',
328 '^components/ntp_snippets/',
329 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51330 '^components/offline_pages/',
331 '^components/omnibox/',
332 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51333 '^components/password_manager/',
334 '^components/payments/',
335 '^components/plugins/',
336 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51337 '^components/proxy_config/',
338 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51339 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51340 '^components/rlz/',
341 '^components/safe_browsing/',
342 '^components/search_engines/',
343 '^components/search_provider_logos/',
344 '^components/security_interstitials/',
345 '^components/security_state/',
346 '^components/services/',
347 '^components/sessions/',
348 '^components/signin/',
349 '^components/ssl_errors/',
350 '^components/storage_monitor/',
351 '^components/subresource_filter/',
352 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51353 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51354 '^components/sync_preferences/',
355 '^components/sync_sessions/',
356 '^components/test/',
357 '^components/tracing/',
358 '^components/translate/',
359 '^components/ukm/',
360 '^components/update_client/',
361 '^components/upload_list/',
362 '^components/variations/',
363 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51364 '^components/webcrypto/',
365 '^components/webdata/',
366 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51367 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20368 '^extensions/browser/',
369 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51370 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51371 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51372 '^ios/chrome/',
373 '^ios/components/',
374 '^ios/net/',
375 '^ios/web/',
376 '^ios/web_view/',
377 '^ipc/',
danakj7a2b7082019-05-21 21:13:51378 '^media/base/',
danakjc8576092019-11-26 19:01:36379 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51380 '^media/cast/',
381 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51382 '^media/filters/',
383 '^media/formats/',
384 '^media/gpu/',
385 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51386 '^media/renderers/',
Steve Kobes334b6ed2020-07-09 07:26:31387 '^net/http/',
388 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51389 '^ppapi/proxy/',
390 '^ppapi/shared_impl/',
391 '^ppapi/tests/',
392 '^ppapi/thunk/',
danakj7a2b7082019-05-21 21:13:51393 '^remoting/host/',
394 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51395 '^services/',
danakj7a2b7082019-05-21 21:13:51396 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51397 '^tools/clang/base_bind_rewriters/', # Intentional.
398 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51399))
[email protected]127f18ec2012-06-16 05:05:59400
Daniel Bratell609102be2019-03-27 20:53:21401# Format: Sequence of tuples containing:
402# * String pattern or, if starting with a slash, a regular expression.
403# * Sequence of strings to show when the pattern matches.
404# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
405# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59406_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20407 (
Dave Tapuska98199b612019-07-10 13:30:44408 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53409 (
410 'New code should not use NULL. Use nullptr instead.',
411 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20412 False,
thomasandersone7caaa9b2017-03-29 19:22:53413 (),
414 ),
Peter Kasting94a56c42019-10-25 21:54:04415 (
416 r'/\busing namespace ',
417 (
418 'Using directives ("using namespace x") are banned by the Google Style',
419 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
420 'Explicitly qualify symbols or use using declarations ("using x::foo").',
421 ),
422 True,
423 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
424 ),
Antonio Gomes07300d02019-03-13 20:59:57425 # Make sure that gtest's FRIEND_TEST() macro is not used; the
426 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
427 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53428 (
[email protected]23e6cbc2012-06-16 18:51:20429 'FRIEND_TEST(',
430 (
[email protected]e3c945502012-06-26 20:01:49431 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20432 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
433 ),
434 False,
[email protected]7345da02012-11-27 14:31:49435 (),
[email protected]23e6cbc2012-06-16 18:51:20436 ),
437 (
Dave Tapuska98199b612019-07-10 13:30:44438 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53439 (
440 'Chrome clients wishing to select events on X windows should use',
441 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
442 'you are selecting events from the GPU process, or if you are using',
443 'an XDisplay other than gfx::GetXDisplay().',
444 ),
445 True,
446 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40447 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04448 r"^ui[\\/]gl[\\/].*\.cc$",
449 r"^media[\\/]gpu[\\/].*\.cc$",
450 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37451 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
452 ),
thomasanderson4b569052016-09-14 20:15:53453 ),
454 (
Tom Anderson74d064b2020-07-08 03:47:32455 r'/\WX?(((Width|Height)(MM)?OfScreen)|(Display(Width|Height)))\(',
456 (
457 'Use the corresponding fields in x11::Screen instead.',
458 ),
459 True,
460 (),
461 ),
462 (
Dave Tapuska98199b612019-07-10 13:30:44463 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20464 (
thomasanderson11aa41d2017-06-08 22:22:38465 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20466 ),
467 True,
468 (
Egor Paskoce145c42018-09-28 19:31:04469 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
470 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
471 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20472 ),
473 ),
474 (
tomhudsone2c14d552016-05-26 17:07:46475 'setMatrixClip',
476 (
477 'Overriding setMatrixClip() is prohibited; ',
478 'the base function is deprecated. ',
479 ),
480 True,
481 (),
482 ),
483 (
[email protected]52657f62013-05-20 05:30:31484 'SkRefPtr',
485 (
486 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22487 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31488 ),
489 True,
490 (),
491 ),
492 (
493 'SkAutoRef',
494 (
495 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22496 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31497 ),
498 True,
499 (),
500 ),
501 (
502 'SkAutoTUnref',
503 (
504 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22505 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31506 ),
507 True,
508 (),
509 ),
510 (
511 'SkAutoUnref',
512 (
513 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
514 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22515 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31516 ),
517 True,
518 (),
519 ),
[email protected]d89eec82013-12-03 14:10:59520 (
521 r'/HANDLE_EINTR\(.*close',
522 (
523 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
524 'descriptor will be closed, and it is incorrect to retry the close.',
525 'Either call close directly and ignore its return value, or wrap close',
526 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
527 ),
528 True,
529 (),
530 ),
531 (
532 r'/IGNORE_EINTR\((?!.*close)',
533 (
534 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
535 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
536 ),
537 True,
538 (
539 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04540 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
541 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59542 ),
543 ),
[email protected]ec5b3f02014-04-04 18:43:43544 (
545 r'/v8::Extension\(',
546 (
547 'Do not introduce new v8::Extensions into the code base, use',
548 'gin::Wrappable instead. See http://crbug.com/334679',
549 ),
550 True,
[email protected]f55c90ee62014-04-12 00:50:03551 (
Egor Paskoce145c42018-09-28 19:31:04552 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03553 ),
[email protected]ec5b3f02014-04-04 18:43:43554 ),
skyostilf9469f72015-04-20 10:38:52555 (
jame2d1a952016-04-02 00:27:10556 '#pragma comment(lib,',
557 (
558 'Specify libraries to link with in build files and not in the source.',
559 ),
560 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41561 (
tzik3f295992018-12-04 20:32:23562 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04563 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41564 ),
jame2d1a952016-04-02 00:27:10565 ),
fdorayc4ac18d2017-05-01 21:39:59566 (
Gabriel Charette7cc6c432018-04-25 20:52:02567 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59568 (
569 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
570 ),
571 False,
572 (),
573 ),
574 (
Gabriel Charette7cc6c432018-04-25 20:52:02575 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59576 (
577 'Consider using THREAD_CHECKER macros instead of the class directly.',
578 ),
579 False,
580 (),
581 ),
dbeamb6f4fde2017-06-15 04:03:06582 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06583 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
584 (
585 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
586 'deprecated (http://crbug.com/634507). Please avoid converting away',
587 'from the Time types in Chromium code, especially if any math is',
588 'being done on time values. For interfacing with platform/library',
589 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
590 'type converter methods instead. For faking TimeXXX values (for unit',
591 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
592 'other use cases, please contact base/time/OWNERS.',
593 ),
594 False,
595 (),
596 ),
597 (
dbeamb6f4fde2017-06-15 04:03:06598 'CallJavascriptFunctionUnsafe',
599 (
600 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
601 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
602 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
603 ),
604 False,
605 (
Egor Paskoce145c42018-09-28 19:31:04606 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
607 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
608 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06609 ),
610 ),
dskiba1474c2bfd62017-07-20 02:19:24611 (
612 'leveldb::DB::Open',
613 (
614 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
615 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
616 "Chrome's tracing, making their memory usage visible.",
617 ),
618 True,
619 (
620 r'^third_party/leveldatabase/.*\.(cc|h)$',
621 ),
Gabriel Charette0592c3a2017-07-26 12:02:04622 ),
623 (
Chris Mumfordc38afb62017-10-09 17:55:08624 'leveldb::NewMemEnv',
625 (
626 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58627 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
628 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08629 ),
630 True,
631 (
632 r'^third_party/leveldatabase/.*\.(cc|h)$',
633 ),
634 ),
635 (
Gabriel Charetted9839bc2017-07-29 14:17:47636 'RunLoop::QuitCurrent',
637 (
Robert Liao64b7ab22017-08-04 23:03:43638 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
639 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47640 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41641 False,
Gabriel Charetted9839bc2017-07-29 14:17:47642 (),
Gabriel Charettea44975052017-08-21 23:14:04643 ),
644 (
645 'base::ScopedMockTimeMessageLoopTaskRunner',
646 (
Gabriel Charette87cc1af2018-04-25 20:52:51647 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11648 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51649 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
650 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
651 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04652 ),
Gabriel Charette87cc1af2018-04-25 20:52:51653 False,
Gabriel Charettea44975052017-08-21 23:14:04654 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57655 ),
656 (
Dave Tapuska98199b612019-07-10 13:30:44657 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57658 (
659 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02660 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57661 ),
662 True,
663 (),
Francois Doray43670e32017-09-27 12:40:38664 ),
665 (
Peter Kasting991618a62019-06-17 22:00:09666 r'/\bstd::stoi\b',
667 (
668 'std::stoi uses exceptions to communicate results. ',
669 'Use base::StringToInt() instead.',
670 ),
671 True,
672 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
673 ),
674 (
675 r'/\bstd::stol\b',
676 (
677 'std::stol uses exceptions to communicate results. ',
678 'Use base::StringToInt() instead.',
679 ),
680 True,
681 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
682 ),
683 (
684 r'/\bstd::stoul\b',
685 (
686 'std::stoul uses exceptions to communicate results. ',
687 'Use base::StringToUint() instead.',
688 ),
689 True,
690 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
691 ),
692 (
693 r'/\bstd::stoll\b',
694 (
695 'std::stoll uses exceptions to communicate results. ',
696 'Use base::StringToInt64() instead.',
697 ),
698 True,
699 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
700 ),
701 (
702 r'/\bstd::stoull\b',
703 (
704 'std::stoull uses exceptions to communicate results. ',
705 'Use base::StringToUint64() instead.',
706 ),
707 True,
708 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
709 ),
710 (
711 r'/\bstd::stof\b',
712 (
713 'std::stof uses exceptions to communicate results. ',
714 'For locale-independent values, e.g. reading numbers from disk',
715 'profiles, use base::StringToDouble().',
716 'For user-visible values, parse using ICU.',
717 ),
718 True,
719 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
720 ),
721 (
722 r'/\bstd::stod\b',
723 (
724 'std::stod uses exceptions to communicate results. ',
725 'For locale-independent values, e.g. reading numbers from disk',
726 'profiles, use base::StringToDouble().',
727 'For user-visible values, parse using ICU.',
728 ),
729 True,
730 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
731 ),
732 (
733 r'/\bstd::stold\b',
734 (
735 'std::stold uses exceptions to communicate results. ',
736 'For locale-independent values, e.g. reading numbers from disk',
737 'profiles, use base::StringToDouble().',
738 'For user-visible values, parse using ICU.',
739 ),
740 True,
741 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
742 ),
743 (
Daniel Bratell69334cc2019-03-26 11:07:45744 r'/\bstd::to_string\b',
745 (
746 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09747 'For locale-independent strings, e.g. writing numbers to disk',
748 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45749 'For user-visible strings, use base::FormatNumber() and',
750 'the related functions in base/i18n/number_formatting.h.',
751 ),
Peter Kasting991618a62019-06-17 22:00:09752 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21753 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45754 ),
755 (
756 r'/\bstd::shared_ptr\b',
757 (
758 'std::shared_ptr should not be used. Use scoped_refptr instead.',
759 ),
760 True,
Alex Chau9eb03cdd52020-07-13 21:04:57761 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
762 'array_buffer_contents\.(cc|h)',
763 # Needed for interop with third-party library
764 'chrome/services/sharing/nearby/',
765 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
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 ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53957 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
958 'operator& is generally recommended. So always use operator& instead. '
959 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28960 ),
961 True,
962 (),
963 ),
Antonio Gomes07300d02019-03-13 20:59:57964 (
965 'DEFINE_TYPE_CASTS',
966 (
967 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
968 '//third_party/blink/renderer/platform/casting.h.'
969 ),
970 True,
971 (
972 r'^third_party/blink/renderer/.*\.(cc|h)$',
973 ),
974 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38975 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45976 r'/\bIsHTML.+Element\(\b',
977 (
978 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
979 ' helpers IsA<HTMLXXXXElement> from ',
980 '//third_party/blink/renderer/platform/casting.h.'
981 ),
982 False,
983 (
984 r'^third_party/blink/renderer/.*\.(cc|h)$',
985 ),
986 ),
987 (
988 r'/\bToHTML.+Element(|OrNull)\(\b',
989 (
990 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
991 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
992 'and DynamicTo<HTMLXXXXElement> from ',
993 '//third_party/blink/renderer/platform/casting.h.'
994 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
995 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
996 ),
997 False,
998 (
999 r'^third_party/blink/renderer/.*\.(cc|h)$',
1000 ),
1001 ),
1002 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371003 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381004 (
1005 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1006 ),
1007 True,
1008 (),
1009 ),
Ben Lewisa9514602019-04-29 17:53:051010 (
1011 'SHFileOperation',
1012 (
1013 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1014 'complex functions to achieve the same goals. Use IFileOperation for ',
1015 'any esoteric actions instead.'
1016 ),
1017 True,
1018 (),
1019 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181020 (
Cliff Smolinsky81951642019-04-30 21:39:511021 'StringFromGUID2',
1022 (
1023 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1024 'Use base::win::String16FromGUID instead.'
1025 ),
1026 True,
1027 (
1028 r'/base/win/win_util_unittest.cc'
1029 ),
1030 ),
1031 (
1032 'StringFromCLSID',
1033 (
1034 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1035 'Use base::win::String16FromGUID instead.'
1036 ),
1037 True,
1038 (
1039 r'/base/win/win_util_unittest.cc'
1040 ),
1041 ),
1042 (
Avi Drissman7382afa02019-04-29 23:27:131043 'kCFAllocatorNull',
1044 (
1045 'The use of kCFAllocatorNull with the NoCopy creation of ',
1046 'CoreFoundation types is prohibited.',
1047 ),
1048 True,
1049 (),
1050 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291051 (
1052 'mojo::ConvertTo',
1053 (
1054 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1055 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1056 'StringTraits if you would like to convert between custom types and',
1057 'the wire format of mojom types.'
1058 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221059 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291060 (
Wezf89dec092019-09-11 19:38:331061 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1062 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291063 r'^third_party/blink/.*\.(cc|h)$',
1064 r'^content/renderer/.*\.(cc|h)$',
1065 ),
1066 ),
Robert Liao1d78df52019-11-11 20:02:011067 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161068 'GetInterfaceProvider',
1069 (
1070 'InterfaceProvider is deprecated.',
1071 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1072 'or Platform::GetBrowserInterfaceBroker.'
1073 ),
1074 False,
1075 (),
1076 ),
1077 (
Robert Liao1d78df52019-11-11 20:02:011078 'CComPtr',
1079 (
1080 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1081 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1082 'details.'
1083 ),
1084 False,
1085 (),
1086 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201087 (
1088 r'/\b(IFACE|STD)METHOD_?\(',
1089 (
1090 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1091 'Instead, always use IFACEMETHODIMP in the declaration.'
1092 ),
1093 False,
1094 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1095 ),
Allen Bauer53b43fb12020-03-12 17:21:471096 (
1097 'set_owned_by_client',
1098 (
1099 'set_owned_by_client is deprecated.',
1100 'views::View already owns the child views by default. This introduces ',
1101 'a competing ownership model which makes the code difficult to reason ',
1102 'about. See http://crbug.com/1044687 for more details.'
1103 ),
1104 False,
1105 (),
1106 ),
Eric Secklerbe6f48d2020-05-06 18:09:121107 (
1108 r'/\bTRACE_EVENT_ASYNC_',
1109 (
1110 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1111 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1112 ),
1113 False,
1114 (
1115 r'^base/trace_event/.*',
1116 r'^base/tracing/.*',
1117 ),
1118 ),
[email protected]127f18ec2012-06-16 05:05:591119)
1120
Mario Sanchez Prada2472cab2019-09-18 10:58:311121# Format: Sequence of tuples containing:
1122# * String pattern or, if starting with a slash, a regular expression.
1123# * Sequence of strings to show when the pattern matches.
1124_DEPRECATED_MOJO_TYPES = (
1125 (
1126 r'/\bmojo::AssociatedBinding\b',
1127 (
1128 'mojo::AssociatedBinding<Interface> is deprecated.',
1129 'Use mojo::AssociatedReceiver<Interface> instead.',
1130 ),
1131 ),
1132 (
1133 r'/\bmojo::AssociatedBindingSet\b',
1134 (
1135 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1136 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1137 ),
1138 ),
1139 (
1140 r'/\bmojo::AssociatedInterfacePtr\b',
1141 (
1142 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1143 'Use mojo::AssociatedRemote<Interface> instead.',
1144 ),
1145 ),
1146 (
1147 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1148 (
1149 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1150 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1151 ),
1152 ),
1153 (
1154 r'/\bmojo::AssociatedInterfaceRequest\b',
1155 (
1156 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1157 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1158 ),
1159 ),
1160 (
1161 r'/\bmojo::Binding\b',
1162 (
1163 'mojo::Binding<Interface> is deprecated.',
1164 'Use mojo::Receiver<Interface> instead.',
1165 ),
1166 ),
1167 (
1168 r'/\bmojo::BindingSet\b',
1169 (
1170 'mojo::BindingSet<Interface> is deprecated.',
1171 'Use mojo::ReceiverSet<Interface> instead.',
1172 ),
1173 ),
1174 (
1175 r'/\bmojo::InterfacePtr\b',
1176 (
1177 'mojo::InterfacePtr<Interface> is deprecated.',
1178 'Use mojo::Remote<Interface> instead.',
1179 ),
1180 ),
1181 (
1182 r'/\bmojo::InterfacePtrInfo\b',
1183 (
1184 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1185 'Use mojo::PendingRemote<Interface> instead.',
1186 ),
1187 ),
1188 (
1189 r'/\bmojo::InterfaceRequest\b',
1190 (
1191 'mojo::InterfaceRequest<Interface> is deprecated.',
1192 'Use mojo::PendingReceiver<Interface> instead.',
1193 ),
1194 ),
1195 (
1196 r'/\bmojo::MakeRequest\b',
1197 (
1198 'mojo::MakeRequest is deprecated.',
1199 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1200 ),
1201 ),
1202 (
1203 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1204 (
1205 'mojo::MakeRequest is deprecated.',
1206 'Use mojo::AssociatedRemote::'
1207 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1208 ),
1209 ),
1210 (
1211 r'/\bmojo::MakeStrongBinding\b',
1212 (
1213 'mojo::MakeStrongBinding is deprecated.',
1214 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1215 'mojo::MakeSelfOwnedReceiver() instead.',
1216 ),
1217 ),
1218 (
1219 r'/\bmojo::MakeStrongAssociatedBinding\b',
1220 (
1221 'mojo::MakeStrongAssociatedBinding is deprecated.',
1222 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1223 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1224 ),
1225 ),
1226 (
Gyuyoung Kim4952ba62020-07-07 07:33:441227 r'/\bmojo::StrongAssociatedBinding\b',
1228 (
1229 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1230 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1231 ),
1232 ),
1233 (
1234 r'/\bmojo::StrongBinding\b',
1235 (
1236 'mojo::StrongBinding<Interface> is deprecated.',
1237 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1238 ),
1239 ),
1240 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311241 r'/\bmojo::StrongAssociatedBindingSet\b',
1242 (
1243 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1244 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1245 ),
1246 ),
1247 (
1248 r'/\bmojo::StrongBindingSet\b',
1249 (
1250 'mojo::StrongBindingSet<Interface> is deprecated.',
1251 'Use mojo::UniqueReceiverSet<Interface> instead.',
1252 ),
1253 ),
1254)
wnwenbdc444e2016-05-25 13:44:151255
mlamouria82272622014-09-16 18:45:041256_IPC_ENUM_TRAITS_DEPRECATED = (
1257 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501258 'See http://www.chromium.org/Home/chromium-security/education/'
1259 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041260
Stephen Martinis97a394142018-06-07 23:06:051261_LONG_PATH_ERROR = (
1262 'Some files included in this CL have file names that are too long (> 200'
1263 ' characters). If committed, these files will cause issues on Windows. See'
1264 ' https://crbug.com/612667 for more details.'
1265)
1266
Shenghua Zhangbfaa38b82017-11-16 21:58:021267_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041268 r".*[\\/]BuildHooksAndroidImpl\.java",
1269 r".*[\\/]LicenseContentProvider\.java",
1270 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281271 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021272]
[email protected]127f18ec2012-06-16 05:05:591273
Mohamed Heikald048240a2019-11-12 16:57:371274# List of image extensions that are used as resources in chromium.
1275_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1276
Sean Kau46e29bc2017-08-28 16:31:161277# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401278_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041279 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401280 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041281 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1282 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041283 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431284 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161285]
1286
1287
[email protected]b00342e7f2013-03-26 16:21:541288_VALID_OS_MACROS = (
1289 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081290 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121292 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541293 'OS_BSD',
1294 'OS_CAT', # For testing.
1295 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041296 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541297 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371298 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541299 'OS_IOS',
1300 'OS_LINUX',
1301 'OS_MACOSX',
1302 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211303 'OS_NACL_NONSFI',
1304 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121305 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541306 'OS_OPENBSD',
1307 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371308 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541309 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541310 'OS_WIN',
1311)
1312
1313
Andrew Grieveb773bad2020-06-05 18:00:381314# These are not checked on the public chromium-presubmit trybot.
1315# Add files here that rely on .py files that exists only for target_os="android"
1316# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401317_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391318 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381319 'build/android/devil_chromium.pydeps',
1320 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1321 'build/android/gyp/jinja_template.pydeps',
1322 'build/android/resource_sizes.pydeps',
1323 'build/android/test_runner.pydeps',
1324 'build/android/test_wrapper/logdog_wrapper.pydeps',
1325 'chrome/android/features/create_stripped_java_factory.pydeps',
1326 'testing/scripts/run_android_wpt.pydeps',
1327 'third_party/android_platform/development/scripts/stack.pydeps',
1328]
1329
1330
1331_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'base/android/jni_generator/jni_generator.pydeps',
1333 'base/android/jni_generator/jni_registration_generator.pydeps',
1334 'build/android/gyp/aar.pydeps',
1335 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271336 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381338 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111340 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111344 'build/android/gyp/create_app_bundle_apks.pydeps',
1345 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121347 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221348 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001349 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591351 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361352 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421353 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/android/gyp/filter_zip.pydeps',
1356 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361357 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581359 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261361 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011362 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361363 'build/android/gyp/lint.pydeps',
1364 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361365 'build/android/gyp/merge_manifest.pydeps',
1366 'build/android/gyp/prepare_resources.pydeps',
1367 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461368 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241369 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361370 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461371 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561372 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361373 'build/android/incremental_install/generate_android_manifest.pydeps',
1374 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361375 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271376 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1377 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001378 'components/cronet/tools/generate_javadoc.pydeps',
1379 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381380 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001381 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381382 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421383 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1384 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131385 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191386 ('third_party/blink/renderer/bindings/scripts/'
1387 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061388 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221389 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401390]
1391
wnwenbdc444e2016-05-25 13:44:151392
agrievef32bcc72016-04-04 14:57:401393_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1394
1395
Eric Boren6fd2b932018-01-25 15:05:081396# Bypass the AUTHORS check for these accounts.
1397_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591398 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451399 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591400 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521401 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1402 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041403 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271404 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041405 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301406 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081407
1408
Daniel Bratell65b033262019-04-23 08:17:061409def _IsCPlusPlusFile(input_api, file_path):
1410 """Returns True if this file contains C++-like code (and not Python,
1411 Go, Java, MarkDown, ...)"""
1412
1413 ext = input_api.os_path.splitext(file_path)[1]
1414 # This list is compatible with CppChecker.IsCppFile but we should
1415 # consider adding ".c" to it. If we do that we can use this function
1416 # at more places in the code.
1417 return ext in (
1418 '.h',
1419 '.cc',
1420 '.cpp',
1421 '.m',
1422 '.mm',
1423 )
1424
1425def _IsCPlusPlusHeaderFile(input_api, file_path):
1426 return input_api.os_path.splitext(file_path)[1] == ".h"
1427
1428
1429def _IsJavaFile(input_api, file_path):
1430 return input_api.os_path.splitext(file_path)[1] == ".java"
1431
1432
1433def _IsProtoFile(input_api, file_path):
1434 return input_api.os_path.splitext(file_path)[1] == ".proto"
1435
[email protected]55459852011-08-10 15:17:191436def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1437 """Attempts to prevent use of functions intended only for testing in
1438 non-testing code. For now this is just a best-effort implementation
1439 that ignores header files and may have some false positives. A
1440 better implementation would probably need a proper C++ parser.
1441 """
1442 # We only scan .cc files and the like, as the declaration of
1443 # for-testing functions in header files are hard to distinguish from
1444 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491445 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191446
jochenc0d4808c2015-07-27 09:25:421447 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191448 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091449 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191450 exclusion_pattern = input_api.re.compile(
1451 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1452 base_function_pattern, base_function_pattern))
1453
1454 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441455 black_list = (_EXCLUDED_PATHS +
1456 _TEST_CODE_EXCLUDED_PATHS +
1457 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191458 return input_api.FilterSourceFile(
1459 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491460 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191461 black_list=black_list)
1462
1463 problems = []
1464 for f in input_api.AffectedSourceFiles(FilterFile):
1465 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241466 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031467 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461468 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031469 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191470 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031471 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191472
1473 if problems:
[email protected]f7051d52013-04-02 18:31:421474 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031475 else:
1476 return []
[email protected]55459852011-08-10 15:17:191477
1478
Vaclav Brozek7dbc28c2018-03-27 08:35:231479def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1480 """This is a simplified version of
1481 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1482 """
1483 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1484 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1485 name_pattern = r'ForTest(s|ing)?'
1486 # Describes an occurrence of "ForTest*" inside a // comment.
1487 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1488 # Catch calls.
1489 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1490 # Ignore definitions. (Comments are ignored separately.)
1491 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1492
1493 problems = []
1494 sources = lambda x: input_api.FilterSourceFile(
1495 x,
1496 black_list=(('(?i).*test', r'.*\/junit\/')
1497 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491498 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231499 )
1500 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1501 local_path = f.LocalPath()
1502 is_inside_javadoc = False
1503 for line_number, line in f.ChangedContents():
1504 if is_inside_javadoc and javadoc_end_re.search(line):
1505 is_inside_javadoc = False
1506 if not is_inside_javadoc and javadoc_start_re.search(line):
1507 is_inside_javadoc = True
1508 if is_inside_javadoc:
1509 continue
1510 if (inclusion_re.search(line) and
1511 not comment_re.search(line) and
1512 not exclusion_re.search(line)):
1513 problems.append(
1514 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1515
1516 if problems:
1517 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1518 else:
1519 return []
1520
1521
[email protected]10689ca2011-09-02 02:31:541522def _CheckNoIOStreamInHeaders(input_api, output_api):
1523 """Checks to make sure no .h files include <iostream>."""
1524 files = []
1525 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1526 input_api.re.MULTILINE)
1527 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1528 if not f.LocalPath().endswith('.h'):
1529 continue
1530 contents = input_api.ReadFile(f)
1531 if pattern.search(contents):
1532 files.append(f)
1533
1534 if len(files):
yolandyandaabc6d2016-04-18 18:29:391535 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061536 'Do not #include <iostream> in header files, since it inserts static '
1537 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541538 '#include <ostream>. See http://crbug.com/94794',
1539 files) ]
1540 return []
1541
Danil Chapovalov3518f362018-08-11 16:13:431542def _CheckNoStrCatRedefines(input_api, output_api):
1543 """Checks no windows headers with StrCat redefined are included directly."""
1544 files = []
1545 pattern_deny = input_api.re.compile(
1546 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1547 input_api.re.MULTILINE)
1548 pattern_allow = input_api.re.compile(
1549 r'^#include\s"base/win/windows_defines.inc"',
1550 input_api.re.MULTILINE)
1551 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1552 contents = input_api.ReadFile(f)
1553 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1554 files.append(f.LocalPath())
1555
1556 if len(files):
1557 return [output_api.PresubmitError(
1558 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1559 'directly since they pollute code with StrCat macro. Instead, '
1560 'include matching header from base/win. See http://crbug.com/856536',
1561 files) ]
1562 return []
1563
[email protected]10689ca2011-09-02 02:31:541564
[email protected]72df4e782012-06-21 16:28:181565def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521566 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181567 problems = []
1568 for f in input_api.AffectedFiles():
1569 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1570 continue
1571
1572 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041573 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181574 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1575
1576 if not problems:
1577 return []
1578 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1579 '\n'.join(problems))]
1580
Dominic Battre033531052018-09-24 15:45:341581def _CheckNoDISABLETypoInTests(input_api, output_api):
1582 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1583
1584 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1585 instead of DISABLED_. To filter false positives, reports are only generated
1586 if a corresponding MAYBE_ line exists.
1587 """
1588 problems = []
1589
1590 # The following two patterns are looked for in tandem - is a test labeled
1591 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1592 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1593 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1594
1595 # This is for the case that a test is disabled on all platforms.
1596 full_disable_pattern = input_api.re.compile(
1597 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1598 input_api.re.MULTILINE)
1599
Katie Df13948e2018-09-25 07:33:441600 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341601 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1602 continue
1603
1604 # Search for MABYE_, DISABLE_ pairs.
1605 disable_lines = {} # Maps of test name to line number.
1606 maybe_lines = {}
1607 for line_num, line in f.ChangedContents():
1608 disable_match = disable_pattern.search(line)
1609 if disable_match:
1610 disable_lines[disable_match.group(1)] = line_num
1611 maybe_match = maybe_pattern.search(line)
1612 if maybe_match:
1613 maybe_lines[maybe_match.group(1)] = line_num
1614
1615 # Search for DISABLE_ occurrences within a TEST() macro.
1616 disable_tests = set(disable_lines.keys())
1617 maybe_tests = set(maybe_lines.keys())
1618 for test in disable_tests.intersection(maybe_tests):
1619 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1620
1621 contents = input_api.ReadFile(f)
1622 full_disable_match = full_disable_pattern.search(contents)
1623 if full_disable_match:
1624 problems.append(' %s' % f.LocalPath())
1625
1626 if not problems:
1627 return []
1628 return [
1629 output_api.PresubmitPromptWarning(
1630 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1631 '\n'.join(problems))
1632 ]
1633
[email protected]72df4e782012-06-21 16:28:181634
danakj61c1aa22015-10-26 19:55:521635def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571636 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521637 errors = []
Hans Wennborg944479f2020-06-25 21:39:251638 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521639 input_api.re.MULTILINE)
1640 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1641 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1642 continue
1643 for lnum, line in f.ChangedContents():
1644 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171645 errors.append(output_api.PresubmitError(
1646 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571647 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171648 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521649 return errors
1650
1651
Makoto Shimazu3ad422cd2019-05-08 02:35:141652def _FindHistogramNameInChunk(histogram_name, chunk):
1653 """Tries to find a histogram name or prefix in a line.
1654
1655 Returns the existence of the histogram name, or None if it needs more chunk
1656 to determine."""
mcasasb7440c282015-02-04 14:52:191657 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1658 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141659 if '<affected-histogram' in chunk:
1660 # If the tag is not completed, needs more chunk to get the name.
1661 if not '>' in chunk:
1662 return None
1663 if not 'name="' in chunk:
1664 return False
1665 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1666 # expect the only attribute is the name.
1667 histogram_prefix = chunk.split('"')[1]
1668 return histogram_prefix in histogram_name
1669 # Typically the whole histogram name should in the line.
1670 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191671
1672
1673def _CheckUmaHistogramChanges(input_api, output_api):
1674 """Check that UMA histogram names in touched lines can still be found in other
1675 lines of the patch or in histograms.xml. Note that this check would not catch
1676 the reverse: changes in histograms.xml not matched in the code itself."""
1677 touched_histograms = []
1678 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471679 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1680 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1681 name_pattern = r'"(.*?)"'
1682 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1683 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1684 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1685 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1686 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171687 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191688 for f in input_api.AffectedFiles():
1689 # If histograms.xml itself is modified, keep the modified lines for later.
1690 if f.LocalPath().endswith(('histograms.xml')):
1691 histograms_xml_modifications = f.ChangedContents()
1692 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471693 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1694 single_line_re = single_line_c_re
1695 split_line_prefix_re = split_line_c_prefix_re
1696 elif f.LocalPath().endswith(('java')):
1697 single_line_re = single_line_java_re
1698 split_line_prefix_re = split_line_java_prefix_re
1699 else:
mcasasb7440c282015-02-04 14:52:191700 continue
1701 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171702 if last_line_matched_prefix:
1703 suffix_found = split_line_suffix_re.search(line)
1704 if suffix_found :
1705 touched_histograms.append([suffix_found.group(1), f, line_num])
1706 last_line_matched_prefix = False
1707 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061708 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191709 if found:
1710 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171711 continue
1712 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191713
1714 # Search for the touched histogram names in the local modifications to
1715 # histograms.xml, and, if not found, on the base histograms.xml file.
1716 unmatched_histograms = []
1717 for histogram_info in touched_histograms:
1718 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141719 chunk = ''
mcasasb7440c282015-02-04 14:52:191720 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141721 chunk += line
1722 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], 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 unmatched_histograms.append(histogram_info)
1730
eromanb90c82e7e32015-04-01 15:13:491731 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191732 problems = []
1733 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491734 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191735 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451736 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191737 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141738 chunk = ''
mcasasb7440c282015-02-04 14:52:191739 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141740 chunk += line
1741 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1742 chunk)
1743 if histogram_name_found is None:
1744 continue
1745 chunk = ''
mcasasb7440c282015-02-04 14:52:191746 if histogram_name_found:
1747 break
1748 if not histogram_name_found:
1749 problems.append(' [%s:%d] %s' %
1750 (f.LocalPath(), line_num, histogram_name))
1751
1752 if not problems:
1753 return []
1754 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1755 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491756 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191757
wnwenbdc444e2016-05-25 13:44:151758
yolandyandaabc6d2016-04-18 18:29:391759def _CheckFlakyTestUsage(input_api, output_api):
1760 """Check that FlakyTest annotation is our own instead of the android one"""
1761 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1762 files = []
1763 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1764 if f.LocalPath().endswith('Test.java'):
1765 if pattern.search(input_api.ReadFile(f)):
1766 files.append(f)
1767 if len(files):
1768 return [output_api.PresubmitError(
1769 'Use org.chromium.base.test.util.FlakyTest instead of '
1770 'android.test.FlakyTest',
1771 files)]
1772 return []
mcasasb7440c282015-02-04 14:52:191773
wnwenbdc444e2016-05-25 13:44:151774
[email protected]8ea5d4b2011-09-13 21:49:221775def _CheckNoNewWStrings(input_api, output_api):
1776 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271777 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221778 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201779 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571780 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341781 '/win/' in f.LocalPath() or
1782 'chrome_elf' in f.LocalPath() or
1783 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201784 continue
[email protected]8ea5d4b2011-09-13 21:49:221785
[email protected]a11dbe9b2012-08-07 01:32:581786 allowWString = False
[email protected]b5c24292011-11-28 14:38:201787 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581788 if 'presubmit: allow wstring' in line:
1789 allowWString = True
1790 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271791 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581792 allowWString = False
1793 else:
1794 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221795
[email protected]55463aa62011-10-12 00:48:271796 if not problems:
1797 return []
1798 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581799 ' If you are calling a cross-platform API that accepts a wstring, '
1800 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271801 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221802
1803
[email protected]2a8ac9c2011-10-19 17:20:441804def _CheckNoDEPSGIT(input_api, output_api):
1805 """Make sure .DEPS.git is never modified manually."""
1806 if any(f.LocalPath().endswith('.DEPS.git') for f in
1807 input_api.AffectedFiles()):
1808 return [output_api.PresubmitError(
1809 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1810 'automated system based on what\'s in DEPS and your changes will be\n'
1811 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501812 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1813 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441814 'for more information')]
1815 return []
1816
1817
tandriief664692014-09-23 14:51:471818def _CheckValidHostsInDEPS(input_api, output_api):
1819 """Checks that DEPS file deps are from allowed_hosts."""
1820 # Run only if DEPS file has been modified to annoy fewer bystanders.
1821 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1822 return []
1823 # Outsource work to gclient verify
1824 try:
John Budorickf20c0042019-04-25 23:23:401825 gclient_path = input_api.os_path.join(
1826 input_api.PresubmitLocalPath(),
1827 'third_party', 'depot_tools', 'gclient.py')
1828 input_api.subprocess.check_output(
1829 [input_api.python_executable, gclient_path, 'verify'],
1830 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471831 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201832 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471833 return [output_api.PresubmitError(
1834 'DEPS file must have only git dependencies.',
1835 long_text=error.output)]
1836
1837
Mario Sanchez Prada2472cab2019-09-18 10:58:311838def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1839 type_name, message):
1840 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1841
1842 Returns an string composed of the name of the file, the line number where the
1843 match has been found and the additional text passed as |message| in case the
1844 target type name matches the text inside the line passed as parameter.
1845 """
Peng Huang9c5949a02020-06-11 19:20:541846 result = []
1847
1848 if line.endswith(" nocheck"):
1849 return result
1850
Mario Sanchez Prada2472cab2019-09-18 10:58:311851 matched = False
1852 if type_name[0:1] == '/':
1853 regex = type_name[1:]
1854 if input_api.re.search(regex, line):
1855 matched = True
1856 elif type_name in line:
1857 matched = True
1858
Mario Sanchez Prada2472cab2019-09-18 10:58:311859 if matched:
1860 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1861 for message_line in message:
1862 result.append(' %s' % message_line)
1863
1864 return result
1865
1866
[email protected]127f18ec2012-06-16 05:05:591867def _CheckNoBannedFunctions(input_api, output_api):
1868 """Make sure that banned functions are not used."""
1869 warnings = []
1870 errors = []
1871
wnwenbdc444e2016-05-25 13:44:151872 def IsBlacklisted(affected_file, blacklist):
1873 local_path = affected_file.LocalPath()
1874 for item in blacklist:
1875 if input_api.re.match(item, local_path):
1876 return True
1877 return False
1878
Peter K. Lee6c03ccff2019-07-15 14:40:051879 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541880 local_path = affected_file.LocalPath()
1881 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1882 return False
1883 basename = input_api.os_path.basename(local_path)
1884 if 'ios' in basename.split('_'):
1885 return True
1886 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1887 if sep and 'ios' in local_path.split(sep):
1888 return True
1889 return False
1890
wnwenbdc444e2016-05-25 13:44:151891 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311892 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1893 func_name, message)
1894 if problems:
wnwenbdc444e2016-05-25 13:44:151895 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311896 errors.extend(problems)
1897 else:
1898 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151899
Eric Stevensona9a980972017-09-23 00:04:411900 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1901 for f in input_api.AffectedFiles(file_filter=file_filter):
1902 for line_num, line in f.ChangedContents():
1903 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1904 CheckForMatch(f, line_num, line, func_name, message, error)
1905
[email protected]127f18ec2012-06-16 05:05:591906 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1907 for f in input_api.AffectedFiles(file_filter=file_filter):
1908 for line_num, line in f.ChangedContents():
1909 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151910 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591911
Peter K. Lee6c03ccff2019-07-15 14:40:051912 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541913 for line_num, line in f.ChangedContents():
1914 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1915 CheckForMatch(f, line_num, line, func_name, message, error)
1916
Peter K. Lee6c03ccff2019-07-15 14:40:051917 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1918 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1919 for line_num, line in f.ChangedContents():
1920 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1921 CheckForMatch(f, line_num, line, func_name, message, error)
1922
[email protected]127f18ec2012-06-16 05:05:591923 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1924 for f in input_api.AffectedFiles(file_filter=file_filter):
1925 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491926 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491927 if IsBlacklisted(f, excluded_paths):
1928 continue
wnwenbdc444e2016-05-25 13:44:151929 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591930
1931 result = []
1932 if (warnings):
1933 result.append(output_api.PresubmitPromptWarning(
1934 'Banned functions were used.\n' + '\n'.join(warnings)))
1935 if (errors):
1936 result.append(output_api.PresubmitError(
1937 'Banned functions were used.\n' + '\n'.join(errors)))
1938 return result
1939
1940
Michael Thiessen44457642020-02-06 00:24:151941def _CheckAndroidNoBannedImports(input_api, output_api):
1942 """Make sure that banned java imports are not used."""
1943 errors = []
1944
1945 def IsException(path, exceptions):
1946 for exception in exceptions:
1947 if (path.startswith(exception)):
1948 return True
1949 return False
1950
1951 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1952 for f in input_api.AffectedFiles(file_filter=file_filter):
1953 for line_num, line in f.ChangedContents():
1954 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1955 if IsException(f.LocalPath(), exceptions):
1956 continue;
1957 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1958 'import ' + import_name, message)
1959 if problems:
1960 errors.extend(problems)
1961 result = []
1962 if (errors):
1963 result.append(output_api.PresubmitError(
1964 'Banned imports were used.\n' + '\n'.join(errors)))
1965 return result
1966
1967
Mario Sanchez Prada2472cab2019-09-18 10:58:311968def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1969 """Make sure that old Mojo types are not used."""
1970 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571971 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311972
Mario Sanchez Pradaaab91382019-12-19 08:57:091973 # For any path that is not an "ok" or an "error" path, a warning will be
1974 # raised if deprecated mojo types are found.
1975 ok_paths = ['components/arc']
1976 error_paths = ['third_party/blink', 'content']
1977
Mario Sanchez Prada2472cab2019-09-18 10:58:311978 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1979 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571980 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091981 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311982 continue
1983
1984 for line_num, line in f.ChangedContents():
1985 for func_name, message in _DEPRECATED_MOJO_TYPES:
1986 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1987 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571988
Mario Sanchez Prada2472cab2019-09-18 10:58:311989 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091990 # Raise errors inside |error_paths| and warnings everywhere else.
1991 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571992 errors.extend(problems)
1993 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311994 warnings.extend(problems)
1995
1996 result = []
1997 if (warnings):
1998 result.append(output_api.PresubmitPromptWarning(
1999 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572000 if (errors):
2001 result.append(output_api.PresubmitError(
2002 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312003 return result
2004
2005
[email protected]6c063c62012-07-11 19:11:062006def _CheckNoPragmaOnce(input_api, output_api):
2007 """Make sure that banned functions are not used."""
2008 files = []
2009 pattern = input_api.re.compile(r'^#pragma\s+once',
2010 input_api.re.MULTILINE)
2011 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2012 if not f.LocalPath().endswith('.h'):
2013 continue
2014 contents = input_api.ReadFile(f)
2015 if pattern.search(contents):
2016 files.append(f)
2017
2018 if files:
2019 return [output_api.PresubmitError(
2020 'Do not use #pragma once in header files.\n'
2021 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2022 files)]
2023 return []
2024
[email protected]127f18ec2012-06-16 05:05:592025
[email protected]e7479052012-09-19 00:26:122026def _CheckNoTrinaryTrueFalse(input_api, output_api):
2027 """Checks to make sure we don't introduce use of foo ? true : false."""
2028 problems = []
2029 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2030 for f in input_api.AffectedFiles():
2031 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2032 continue
2033
2034 for line_num, line in f.ChangedContents():
2035 if pattern.match(line):
2036 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2037
2038 if not problems:
2039 return []
2040 return [output_api.PresubmitPromptWarning(
2041 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2042 '\n'.join(problems))]
2043
2044
[email protected]55f9f382012-07-31 11:02:182045def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282046 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182047 change. Breaking - rules is an error, breaking ! rules is a
2048 warning.
2049 """
mohan.reddyf21db962014-10-16 12:26:472050 import sys
[email protected]55f9f382012-07-31 11:02:182051 # We need to wait until we have an input_api object and use this
2052 # roundabout construct to import checkdeps because this file is
2053 # eval-ed and thus doesn't have __file__.
2054 original_sys_path = sys.path
2055 try:
2056 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472057 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182058 import checkdeps
[email protected]55f9f382012-07-31 11:02:182059 from rules import Rule
2060 finally:
2061 # Restore sys.path to what it was before.
2062 sys.path = original_sys_path
2063
2064 added_includes = []
rhalavati08acd232017-04-03 07:23:282065 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242066 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182067 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062068 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502069 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082070 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062071 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502072 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082073 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062074 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502075 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082076 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182077
[email protected]26385172013-05-09 23:11:352078 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182079
2080 error_descriptions = []
2081 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282082 error_subjects = set()
2083 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182084 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2085 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082086 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182087 description_with_path = '%s\n %s' % (path, rule_description)
2088 if rule_type == Rule.DISALLOW:
2089 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282090 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182091 else:
2092 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282093 warning_subjects.add("#includes")
2094
2095 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2096 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082097 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282098 description_with_path = '%s\n %s' % (path, rule_description)
2099 if rule_type == Rule.DISALLOW:
2100 error_descriptions.append(description_with_path)
2101 error_subjects.add("imports")
2102 else:
2103 warning_descriptions.append(description_with_path)
2104 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182105
Jinsuk Kim5a092672017-10-24 22:42:242106 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022107 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082108 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242109 description_with_path = '%s\n %s' % (path, rule_description)
2110 if rule_type == Rule.DISALLOW:
2111 error_descriptions.append(description_with_path)
2112 error_subjects.add("imports")
2113 else:
2114 warning_descriptions.append(description_with_path)
2115 warning_subjects.add("imports")
2116
[email protected]55f9f382012-07-31 11:02:182117 results = []
2118 if error_descriptions:
2119 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282120 'You added one or more %s that violate checkdeps rules.'
2121 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182122 error_descriptions))
2123 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422124 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282125 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182126 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282127 '%s? See relevant DEPS file(s) for details and contacts.' %
2128 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182129 warning_descriptions))
2130 return results
2131
2132
[email protected]fbcafe5a2012-08-08 15:31:222133def _CheckFilePermissions(input_api, output_api):
2134 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152135 if input_api.platform == 'win32':
2136 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292137 checkperms_tool = input_api.os_path.join(
2138 input_api.PresubmitLocalPath(),
2139 'tools', 'checkperms', 'checkperms.py')
2140 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472141 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392142 with input_api.CreateTemporaryFile() as file_list:
2143 for f in input_api.AffectedFiles():
2144 # checkperms.py file/directory arguments must be relative to the
2145 # repository.
2146 file_list.write(f.LocalPath() + '\n')
2147 file_list.close()
2148 args += ['--file-list', file_list.name]
2149 try:
2150 input_api.subprocess.check_output(args)
2151 return []
2152 except input_api.subprocess.CalledProcessError as error:
2153 return [output_api.PresubmitError(
2154 'checkperms.py failed:',
2155 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222156
2157
robertocn832f5992017-01-04 19:01:302158def _CheckTeamTags(input_api, output_api):
2159 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2160 checkteamtags_tool = input_api.os_path.join(
2161 input_api.PresubmitLocalPath(),
2162 'tools', 'checkteamtags', 'checkteamtags.py')
2163 args = [input_api.python_executable, checkteamtags_tool,
2164 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222165 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302166 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2167 'OWNERS']
2168 try:
2169 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052170 warnings = input_api.subprocess.check_output(args + files).splitlines()
2171 if warnings:
2172 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302173 return []
2174 except input_api.subprocess.CalledProcessError as error:
2175 return [output_api.PresubmitError(
2176 'checkteamtags.py failed:',
2177 long_text=error.output)]
2178
2179
[email protected]c8278b32012-10-30 20:35:492180def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2181 """Makes sure we don't include ui/aura/window_property.h
2182 in header files.
2183 """
2184 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2185 errors = []
2186 for f in input_api.AffectedFiles():
2187 if not f.LocalPath().endswith('.h'):
2188 continue
2189 for line_num, line in f.ChangedContents():
2190 if pattern.match(line):
2191 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2192
2193 results = []
2194 if errors:
2195 results.append(output_api.PresubmitError(
2196 'Header files should not include ui/aura/window_property.h', errors))
2197 return results
2198
2199
[email protected]70ca77752012-11-20 03:45:032200def _CheckForVersionControlConflictsInFile(input_api, f):
2201 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2202 errors = []
2203 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162204 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232205 # First-level headers in markdown look a lot like version control
2206 # conflict markers. http://daringfireball.net/projects/markdown/basics
2207 continue
[email protected]70ca77752012-11-20 03:45:032208 if pattern.match(line):
2209 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2210 return errors
2211
2212
2213def _CheckForVersionControlConflicts(input_api, output_api):
2214 """Usually this is not intentional and will cause a compile failure."""
2215 errors = []
2216 for f in input_api.AffectedFiles():
2217 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2218
2219 results = []
2220 if errors:
2221 results.append(output_api.PresubmitError(
2222 'Version control conflict markers found, please resolve.', errors))
2223 return results
2224
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202225
estadee17314a02017-01-12 16:22:162226def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2227 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2228 errors = []
2229 for f in input_api.AffectedFiles():
2230 for line_num, line in f.ChangedContents():
2231 if pattern.search(line):
2232 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2233
2234 results = []
2235 if errors:
2236 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502237 'Found Google support URL addressed by answer number. Please replace '
2238 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162239 return results
2240
[email protected]70ca77752012-11-20 03:45:032241
[email protected]06e6d0ff2012-12-11 01:36:442242def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2243 def FilterFile(affected_file):
2244 """Filter function for use with input_api.AffectedSourceFiles,
2245 below. This filters out everything except non-test files from
2246 top-level directories that generally speaking should not hard-code
2247 service URLs (e.g. src/android_webview/, src/content/ and others).
2248 """
2249 return input_api.FilterSourceFile(
2250 affected_file,
Egor Paskoce145c42018-09-28 19:31:042251 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442252 black_list=(_EXCLUDED_PATHS +
2253 _TEST_CODE_EXCLUDED_PATHS +
2254 input_api.DEFAULT_BLACK_LIST))
2255
reillyi38965732015-11-16 18:27:332256 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2257 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462258 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2259 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442260 problems = [] # items are (filename, line_number, line)
2261 for f in input_api.AffectedSourceFiles(FilterFile):
2262 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462263 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442264 problems.append((f.LocalPath(), line_num, line))
2265
2266 if problems:
[email protected]f7051d52013-04-02 18:31:422267 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442268 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582269 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442270 [' %s:%d: %s' % (
2271 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032272 else:
2273 return []
[email protected]06e6d0ff2012-12-11 01:36:442274
2275
James Cook6b6597c2019-11-06 22:05:292276def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2277 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2278 def FileFilter(affected_file):
2279 """Includes directories known to be Chrome OS only."""
2280 return input_api.FilterSourceFile(
2281 affected_file,
2282 white_list=('^ash/',
2283 '^chromeos/', # Top-level src/chromeos.
2284 '/chromeos/', # Any path component.
2285 '^components/arc',
2286 '^components/exo'),
2287 black_list=(input_api.DEFAULT_BLACK_LIST))
2288
2289 prefs = []
2290 priority_prefs = []
2291 for f in input_api.AffectedFiles(file_filter=FileFilter):
2292 for line_num, line in f.ChangedContents():
2293 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2294 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2295 prefs.append(' %s' % line)
2296 if input_api.re.search(
2297 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2298 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2299 priority_prefs.append(' %s' % line)
2300
2301 results = []
2302 if (prefs):
2303 results.append(output_api.PresubmitPromptWarning(
2304 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2305 'by browser sync settings. If these prefs should be controlled by OS '
2306 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2307 if (priority_prefs):
2308 results.append(output_api.PresubmitPromptWarning(
2309 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2310 'controlled by browser sync settings. If these prefs should be '
2311 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2312 'instead.\n' + '\n'.join(prefs)))
2313 return results
2314
2315
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492316# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272317def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2318 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312319 The native_client_sdk directory is excluded because it has auto-generated PNG
2320 files for documentation.
[email protected]d2530012013-01-25 16:39:272321 """
[email protected]d2530012013-01-25 16:39:272322 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492323 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042324 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312325 file_filter = lambda f: input_api.FilterSourceFile(
2326 f, white_list=white_list, black_list=black_list)
2327 for f in input_api.AffectedFiles(include_deletes=False,
2328 file_filter=file_filter):
2329 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272330
2331 results = []
2332 if errors:
2333 results.append(output_api.PresubmitError(
2334 'The name of PNG files should not have abbreviations. \n'
2335 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2336 'Contact [email protected] if you have questions.', errors))
2337 return results
2338
2339
Daniel Cheng4dcdb6b2017-04-13 08:30:172340def _ExtractAddRulesFromParsedDeps(parsed_deps):
2341 """Extract the rules that add dependencies from a parsed DEPS file.
2342
2343 Args:
2344 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2345 add_rules = set()
2346 add_rules.update([
2347 rule[1:] for rule in parsed_deps.get('include_rules', [])
2348 if rule.startswith('+') or rule.startswith('!')
2349 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502350 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172351 {}).iteritems():
2352 add_rules.update([
2353 rule[1:] for rule in rules
2354 if rule.startswith('+') or rule.startswith('!')
2355 ])
2356 return add_rules
2357
2358
2359def _ParseDeps(contents):
2360 """Simple helper for parsing DEPS files."""
2361 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172362 class _VarImpl:
2363
2364 def __init__(self, local_scope):
2365 self._local_scope = local_scope
2366
2367 def Lookup(self, var_name):
2368 """Implements the Var syntax."""
2369 try:
2370 return self._local_scope['vars'][var_name]
2371 except KeyError:
2372 raise Exception('Var is not defined: %s' % var_name)
2373
2374 local_scope = {}
2375 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172376 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592377 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172378 }
2379 exec contents in global_scope, local_scope
2380 return local_scope
2381
2382
2383def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082384 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412385 a set of DEPS entries that we should look up.
2386
2387 For a directory (rather than a specific filename) we fake a path to
2388 a specific filename by adding /DEPS. This is chosen as a file that
2389 will seldom or never be subject to per-file include_rules.
2390 """
[email protected]2b438d62013-11-14 17:54:142391 # We ignore deps entries on auto-generated directories.
2392 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082393
Daniel Cheng4dcdb6b2017-04-13 08:30:172394 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2395 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2396
2397 added_deps = new_deps.difference(old_deps)
2398
[email protected]2b438d62013-11-14 17:54:142399 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172400 for added_dep in added_deps:
2401 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2402 continue
2403 # Assume that a rule that ends in .h is a rule for a specific file.
2404 if added_dep.endswith('.h'):
2405 results.add(added_dep)
2406 else:
2407 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082408 return results
2409
2410
[email protected]e871964c2013-05-13 14:14:552411def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2412 """When a dependency prefixed with + is added to a DEPS file, we
2413 want to make sure that the change is reviewed by an OWNER of the
2414 target file or directory, to avoid layering violations from being
2415 introduced. This check verifies that this happens.
2416 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172417 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242418
2419 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492420 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242421 for f in input_api.AffectedFiles(include_deletes=False,
2422 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552423 filename = input_api.os_path.basename(f.LocalPath())
2424 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172425 virtual_depended_on_files.update(_CalculateAddedDeps(
2426 input_api.os_path,
2427 '\n'.join(f.OldContents()),
2428 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552429
[email protected]e871964c2013-05-13 14:14:552430 if not virtual_depended_on_files:
2431 return []
2432
2433 if input_api.is_committing:
2434 if input_api.tbr:
2435 return [output_api.PresubmitNotifyResult(
2436 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272437 if input_api.dry_run:
2438 return [output_api.PresubmitNotifyResult(
2439 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552440 if not input_api.change.issue:
2441 return [output_api.PresubmitError(
2442 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402443 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552444 output = output_api.PresubmitError
2445 else:
2446 output = output_api.PresubmitNotifyResult
2447
2448 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502449 owner_email, reviewers = (
2450 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2451 input_api,
2452 owners_db.email_regexp,
2453 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552454
2455 owner_email = owner_email or input_api.change.author_email
2456
[email protected]de4f7d22013-05-23 14:27:462457 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512458 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462459 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552460 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2461 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412462
2463 # We strip the /DEPS part that was added by
2464 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2465 # directory.
2466 def StripDeps(path):
2467 start_deps = path.rfind('/DEPS')
2468 if start_deps != -1:
2469 return path[:start_deps]
2470 else:
2471 return path
2472 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552473 for path in missing_files]
2474
2475 if unapproved_dependencies:
2476 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152477 output('You need LGTM from owners of depends-on paths in DEPS that were '
2478 'modified in this CL:\n %s' %
2479 '\n '.join(sorted(unapproved_dependencies)))]
2480 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2481 output_list.append(output(
2482 'Suggested missing target path OWNERS:\n %s' %
2483 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552484 return output_list
2485
2486 return []
2487
2488
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492489# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402490def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492491 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402492 black_list = (_EXCLUDED_PATHS +
2493 _TEST_CODE_EXCLUDED_PATHS +
2494 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042495 (r"^base[\\/]logging\.h$",
2496 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222497 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042498 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2499 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2500 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122501 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182502 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152503 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032504 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152505 r"^chrome[\\/]chrome_cleaner[\\/].*",
2506 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2507 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042508 r"^chromecast[\\/]",
2509 r"^cloud_print[\\/]",
2510 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482511 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052512 r"^components[\\/]media_control[\\/]renderer[\\/]"
2513 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042514 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462515 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042516 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462517 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042518 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252519 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042520 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2521 r"^courgette[\\/]courgette_tool\.cc$",
2522 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272523 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002524 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332525 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042526 r"^ipc[\\/]ipc_logging\.cc$",
2527 r"^native_client_sdk[\\/]",
2528 r"^remoting[\\/]base[\\/]logging\.h$",
2529 r"^remoting[\\/]host[\\/].*",
2530 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062531 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332532 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042533 r"^tools[\\/]",
2534 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2535 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:372536 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2537 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2538 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402539 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492540 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402541
thomasanderson625d3932017-03-29 07:16:582542 log_info = set([])
2543 printf = set([])
[email protected]85218562013-11-22 07:41:402544
2545 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582546 for _, line in f.ChangedContents():
2547 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2548 log_info.add(f.LocalPath())
2549 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2550 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372551
thomasanderson625d3932017-03-29 07:16:582552 if input_api.re.search(r"\bprintf\(", line):
2553 printf.add(f.LocalPath())
2554 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2555 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402556
2557 if log_info:
2558 return [output_api.PresubmitError(
2559 'These files spam the console log with LOG(INFO):',
2560 items=log_info)]
2561 if printf:
2562 return [output_api.PresubmitError(
2563 'These files spam the console log with printf/fprintf:',
2564 items=printf)]
2565 return []
2566
2567
[email protected]49aa76a2013-12-04 06:59:162568def _CheckForAnonymousVariables(input_api, output_api):
2569 """These types are all expected to hold locks while in scope and
2570 so should never be anonymous (which causes them to be immediately
2571 destroyed)."""
2572 they_who_must_be_named = [
2573 'base::AutoLock',
2574 'base::AutoReset',
2575 'base::AutoUnlock',
2576 'SkAutoAlphaRestore',
2577 'SkAutoBitmapShaderInstall',
2578 'SkAutoBlitterChoose',
2579 'SkAutoBounderCommit',
2580 'SkAutoCallProc',
2581 'SkAutoCanvasRestore',
2582 'SkAutoCommentBlock',
2583 'SkAutoDescriptor',
2584 'SkAutoDisableDirectionCheck',
2585 'SkAutoDisableOvalCheck',
2586 'SkAutoFree',
2587 'SkAutoGlyphCache',
2588 'SkAutoHDC',
2589 'SkAutoLockColors',
2590 'SkAutoLockPixels',
2591 'SkAutoMalloc',
2592 'SkAutoMaskFreeImage',
2593 'SkAutoMutexAcquire',
2594 'SkAutoPathBoundsUpdate',
2595 'SkAutoPDFRelease',
2596 'SkAutoRasterClipValidate',
2597 'SkAutoRef',
2598 'SkAutoTime',
2599 'SkAutoTrace',
2600 'SkAutoUnref',
2601 ]
2602 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2603 # bad: base::AutoLock(lock.get());
2604 # not bad: base::AutoLock lock(lock.get());
2605 bad_pattern = input_api.re.compile(anonymous)
2606 # good: new base::AutoLock(lock.get())
2607 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2608 errors = []
2609
2610 for f in input_api.AffectedFiles():
2611 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2612 continue
2613 for linenum, line in f.ChangedContents():
2614 if bad_pattern.search(line) and not good_pattern.search(line):
2615 errors.append('%s:%d' % (f.LocalPath(), linenum))
2616
2617 if errors:
2618 return [output_api.PresubmitError(
2619 'These lines create anonymous variables that need to be named:',
2620 items=errors)]
2621 return []
2622
2623
Peter Kasting4844e46e2018-02-23 07:27:102624def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532625 # Returns whether |template_str| is of the form <T, U...> for some types T
2626 # and U. Assumes that |template_str| is already in the form <...>.
2627 def HasMoreThanOneArg(template_str):
2628 # Level of <...> nesting.
2629 nesting = 0
2630 for c in template_str:
2631 if c == '<':
2632 nesting += 1
2633 elif c == '>':
2634 nesting -= 1
2635 elif c == ',' and nesting == 1:
2636 return True
2637 return False
2638
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492639 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102640 sources = lambda affected_file: input_api.FilterSourceFile(
2641 affected_file,
2642 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2643 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492644 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552645
2646 # Pattern to capture a single "<...>" block of template arguments. It can
2647 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2648 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2649 # latter would likely require counting that < and > match, which is not
2650 # expressible in regular languages. Should the need arise, one can introduce
2651 # limited counting (matching up to a total number of nesting depth), which
2652 # should cover all practical cases for already a low nesting limit.
2653 template_arg_pattern = (
2654 r'<[^>]*' # Opening block of <.
2655 r'>([^<]*>)?') # Closing block of >.
2656 # Prefix expressing that whatever follows is not already inside a <...>
2657 # block.
2658 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102659 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552660 not_inside_template_arg_pattern
2661 + r'\bstd::unique_ptr'
2662 + template_arg_pattern
2663 + r'\(\)')
2664
2665 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2666 template_arg_no_array_pattern = (
2667 r'<[^>]*[^]]' # Opening block of <.
2668 r'>([^(<]*[^]]>)?') # Closing block of >.
2669 # Prefix saying that what follows is the start of an expression.
2670 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2671 # Suffix saying that what follows are call parentheses with a non-empty list
2672 # of arguments.
2673 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532674 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552675 return_construct_pattern = input_api.re.compile(
2676 start_of_expr_pattern
2677 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532678 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552679 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532680 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552681 + nonempty_arg_list_pattern)
2682
Vaclav Brozek851d9602018-04-04 16:13:052683 problems_constructor = []
2684 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102685 for f in input_api.AffectedSourceFiles(sources):
2686 for line_number, line in f.ChangedContents():
2687 # Disallow:
2688 # return std::unique_ptr<T>(foo);
2689 # bar = std::unique_ptr<T>(foo);
2690 # But allow:
2691 # return std::unique_ptr<T[]>(foo);
2692 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532693 # And also allow cases when the second template argument is present. Those
2694 # cases cannot be handled by std::make_unique:
2695 # return std::unique_ptr<T, U>(foo);
2696 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052697 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532698 return_construct_result = return_construct_pattern.search(line)
2699 if return_construct_result and not HasMoreThanOneArg(
2700 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052701 problems_constructor.append(
2702 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102703 # Disallow:
2704 # std::unique_ptr<T>()
2705 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052706 problems_nullptr.append(
2707 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2708
2709 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162710 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052711 errors.append(output_api.PresubmitError(
2712 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162713 problems_nullptr))
2714 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052715 errors.append(output_api.PresubmitError(
2716 'The following files use explicit std::unique_ptr constructor.'
2717 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162718 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102719 return errors
2720
2721
[email protected]999261d2014-03-03 20:08:082722def _CheckUserActionUpdate(input_api, output_api):
2723 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522724 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082725 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522726 # If actions.xml is already included in the changelist, the PRESUBMIT
2727 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082728 return []
2729
[email protected]999261d2014-03-03 20:08:082730 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2731 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522732 current_actions = None
[email protected]999261d2014-03-03 20:08:082733 for f in input_api.AffectedFiles(file_filter=file_filter):
2734 for line_num, line in f.ChangedContents():
2735 match = input_api.re.search(action_re, line)
2736 if match:
[email protected]2f92dec2014-03-07 19:21:522737 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2738 # loaded only once.
2739 if not current_actions:
2740 with open('tools/metrics/actions/actions.xml') as actions_f:
2741 current_actions = actions_f.read()
2742 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082743 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522744 action = 'name="{0}"'.format(action_name)
2745 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082746 return [output_api.PresubmitPromptWarning(
2747 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522748 'tools/metrics/actions/actions.xml. Please run '
2749 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082750 % (f.LocalPath(), line_num, action_name))]
2751 return []
2752
2753
Daniel Cheng13ca61a882017-08-25 15:11:252754def _ImportJSONCommentEater(input_api):
2755 import sys
2756 sys.path = sys.path + [input_api.os_path.join(
2757 input_api.PresubmitLocalPath(),
2758 'tools', 'json_comment_eater')]
2759 import json_comment_eater
2760 return json_comment_eater
2761
2762
[email protected]99171a92014-06-03 08:44:472763def _GetJSONParseError(input_api, filename, eat_comments=True):
2764 try:
2765 contents = input_api.ReadFile(filename)
2766 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252767 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132768 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472769
2770 input_api.json.loads(contents)
2771 except ValueError as e:
2772 return e
2773 return None
2774
2775
2776def _GetIDLParseError(input_api, filename):
2777 try:
2778 contents = input_api.ReadFile(filename)
2779 idl_schema = input_api.os_path.join(
2780 input_api.PresubmitLocalPath(),
2781 'tools', 'json_schema_compiler', 'idl_schema.py')
2782 process = input_api.subprocess.Popen(
2783 [input_api.python_executable, idl_schema],
2784 stdin=input_api.subprocess.PIPE,
2785 stdout=input_api.subprocess.PIPE,
2786 stderr=input_api.subprocess.PIPE,
2787 universal_newlines=True)
2788 (_, error) = process.communicate(input=contents)
2789 return error or None
2790 except ValueError as e:
2791 return e
2792
2793
2794def _CheckParseErrors(input_api, output_api):
2795 """Check that IDL and JSON files do not contain syntax errors."""
2796 actions = {
2797 '.idl': _GetIDLParseError,
2798 '.json': _GetJSONParseError,
2799 }
[email protected]99171a92014-06-03 08:44:472800 # Most JSON files are preprocessed and support comments, but these do not.
2801 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042802 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472803 ]
2804 # Only run IDL checker on files in these directories.
2805 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042806 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2807 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472808 ]
2809
2810 def get_action(affected_file):
2811 filename = affected_file.LocalPath()
2812 return actions.get(input_api.os_path.splitext(filename)[1])
2813
[email protected]99171a92014-06-03 08:44:472814 def FilterFile(affected_file):
2815 action = get_action(affected_file)
2816 if not action:
2817 return False
2818 path = affected_file.LocalPath()
2819
Erik Staab2dd72b12020-04-16 15:03:402820 if _MatchesFile(input_api,
2821 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2822 path):
[email protected]99171a92014-06-03 08:44:472823 return False
2824
2825 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162826 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472827 return False
2828 return True
2829
2830 results = []
2831 for affected_file in input_api.AffectedFiles(
2832 file_filter=FilterFile, include_deletes=False):
2833 action = get_action(affected_file)
2834 kwargs = {}
2835 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162836 _MatchesFile(input_api, json_no_comments_patterns,
2837 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472838 kwargs['eat_comments'] = False
2839 parse_error = action(input_api,
2840 affected_file.AbsoluteLocalPath(),
2841 **kwargs)
2842 if parse_error:
2843 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2844 (affected_file.LocalPath(), parse_error)))
2845 return results
2846
2847
[email protected]760deea2013-12-10 19:33:492848def _CheckJavaStyle(input_api, output_api):
2849 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472850 import sys
[email protected]760deea2013-12-10 19:33:492851 original_sys_path = sys.path
2852 try:
2853 sys.path = sys.path + [input_api.os_path.join(
2854 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2855 import checkstyle
2856 finally:
2857 # Restore sys.path to what it was before.
2858 sys.path = original_sys_path
2859
2860 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092861 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512862 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492863
2864
Nate Fischerdfd9812e2019-07-18 22:03:002865def _CheckPythonDevilInit(input_api, output_api):
2866 """Checks to make sure devil is initialized correctly in python scripts."""
2867 script_common_initialize_pattern = input_api.re.compile(
2868 r'script_common\.InitializeEnvironment\(')
2869 devil_env_config_initialize = input_api.re.compile(
2870 r'devil_env\.config\.Initialize\(')
2871
2872 errors = []
2873
2874 sources = lambda affected_file: input_api.FilterSourceFile(
2875 affected_file,
2876 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2877 (r'^build[\\/]android[\\/]devil_chromium\.py',
2878 r'^third_party[\\/].*',)),
2879 white_list=[r'.*\.py$'])
2880
2881 for f in input_api.AffectedSourceFiles(sources):
2882 for line_num, line in f.ChangedContents():
2883 if (script_common_initialize_pattern.search(line) or
2884 devil_env_config_initialize.search(line)):
2885 errors.append("%s:%d" % (f.LocalPath(), line_num))
2886
2887 results = []
2888
2889 if errors:
2890 results.append(output_api.PresubmitError(
2891 'Devil initialization should always be done using '
2892 'devil_chromium.Initialize() in the chromium project, to use better '
2893 'defaults for dependencies (ex. up-to-date version of adb).',
2894 errors))
2895
2896 return results
2897
2898
Sean Kau46e29bc2017-08-28 16:31:162899def _MatchesFile(input_api, patterns, path):
2900 for pattern in patterns:
2901 if input_api.re.search(pattern, path):
2902 return True
2903 return False
2904
2905
Daniel Cheng7052cdf2017-11-21 19:23:292906def _GetOwnersFilesToCheckForIpcOwners(input_api):
2907 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172908
Daniel Cheng7052cdf2017-11-21 19:23:292909 Returns:
2910 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2911 contain to cover IPC-related files with noparent reviewer rules.
2912 """
2913 # Whether or not a file affects IPC is (mostly) determined by a simple list
2914 # of filename patterns.
dchenge07de812016-06-20 19:27:172915 file_patterns = [
palmerb19a0932017-01-24 04:00:312916 # Legacy IPC:
dchenge07de812016-06-20 19:27:172917 '*_messages.cc',
2918 '*_messages*.h',
2919 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312920 # Mojo IPC:
dchenge07de812016-06-20 19:27:172921 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472922 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172923 '*_struct_traits*.*',
2924 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312925 '*.typemap',
2926 # Android native IPC:
2927 '*.aidl',
2928 # Blink uses a different file naming convention:
2929 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472930 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172931 '*StructTraits*.*',
2932 '*TypeConverter*.*',
2933 ]
2934
scottmg7a6ed5ba2016-11-04 18:22:042935 # These third_party directories do not contain IPCs, but contain files
2936 # matching the above patterns, which trigger false positives.
2937 exclude_paths = [
2938 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162939 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232940 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292941 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542942 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162943 # These files are just used to communicate between class loaders running
2944 # in the same process.
2945 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572946 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2947
scottmg7a6ed5ba2016-11-04 18:22:042948 ]
2949
dchenge07de812016-06-20 19:27:172950 # Dictionary mapping an OWNERS file path to Patterns.
2951 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2952 # rules ) to a PatternEntry.
2953 # PatternEntry is a dictionary with two keys:
2954 # - 'files': the files that are matched by this pattern
2955 # - 'rules': the per-file rules needed for this pattern
2956 # For example, if we expect OWNERS file to contain rules for *.mojom and
2957 # *_struct_traits*.*, Patterns might look like this:
2958 # {
2959 # '*.mojom': {
2960 # 'files': ...,
2961 # 'rules': [
2962 # 'per-file *.mojom=set noparent',
2963 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2964 # ],
2965 # },
2966 # '*_struct_traits*.*': {
2967 # 'files': ...,
2968 # 'rules': [
2969 # 'per-file *_struct_traits*.*=set noparent',
2970 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2971 # ],
2972 # },
2973 # }
2974 to_check = {}
2975
Daniel Cheng13ca61a882017-08-25 15:11:252976 def AddPatternToCheck(input_file, pattern):
2977 owners_file = input_api.os_path.join(
2978 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2979 if owners_file not in to_check:
2980 to_check[owners_file] = {}
2981 if pattern not in to_check[owners_file]:
2982 to_check[owners_file][pattern] = {
2983 'files': [],
2984 'rules': [
2985 'per-file %s=set noparent' % pattern,
2986 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2987 ]
2988 }
Vaclav Brozekd5de76a2018-03-17 07:57:502989 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252990
dchenge07de812016-06-20 19:27:172991 # Iterate through the affected files to see what we actually need to check
2992 # for. We should only nag patch authors about per-file rules if a file in that
2993 # directory would match that pattern. If a directory only contains *.mojom
2994 # files and no *_messages*.h files, we should only nag about rules for
2995 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252996 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262997 # Manifest files don't have a strong naming convention. Instead, try to find
2998 # affected .cc and .h files which look like they contain a manifest
2999 # definition.
3000 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3001 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3002 if (manifest_pattern.search(f.LocalPath()) and not
3003 test_manifest_pattern.search(f.LocalPath())):
3004 # We expect all actual service manifest files to contain at least one
3005 # qualified reference to service_manager::Manifest.
3006 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253007 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173008 for pattern in file_patterns:
3009 if input_api.fnmatch.fnmatch(
3010 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043011 skip = False
3012 for exclude in exclude_paths:
3013 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3014 skip = True
3015 break
3016 if skip:
3017 continue
Daniel Cheng13ca61a882017-08-25 15:11:253018 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173019 break
3020
Daniel Cheng7052cdf2017-11-21 19:23:293021 return to_check
3022
3023
Wez17c66962020-04-29 15:26:033024def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3025 """Adds OWNERS files to check for correct Fuchsia security owners."""
3026
3027 file_patterns = [
3028 # Component specifications.
3029 '*.cml', # Component Framework v2.
3030 '*.cmx', # Component Framework v1.
3031
3032 # Fuchsia IDL protocol specifications.
3033 '*.fidl',
3034 ]
3035
3036 def AddPatternToCheck(input_file, pattern):
3037 owners_file = input_api.os_path.join(
3038 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3039 if owners_file not in to_check:
3040 to_check[owners_file] = {}
3041 if pattern not in to_check[owners_file]:
3042 to_check[owners_file][pattern] = {
3043 'files': [],
3044 'rules': [
3045 'per-file %s=set noparent' % pattern,
3046 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3047 ]
3048 }
3049 to_check[owners_file][pattern]['files'].append(input_file)
3050
3051 # Iterate through the affected files to see what we actually need to check
3052 # for. We should only nag patch authors about per-file rules if a file in that
3053 # directory would match that pattern.
3054 for f in input_api.AffectedFiles(include_deletes=False):
3055 for pattern in file_patterns:
3056 if input_api.fnmatch.fnmatch(
3057 input_api.os_path.basename(f.LocalPath()), pattern):
3058 AddPatternToCheck(f, pattern)
3059 break
3060
3061 return to_check
3062
3063
3064def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293065 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3066 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033067 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293068
3069 if to_check:
3070 # If there are any OWNERS files to check, there are IPC-related changes in
3071 # this CL. Auto-CC the review list.
3072 output_api.AppendCC('[email protected]')
3073
3074 # Go through the OWNERS files to check, filtering out rules that are already
3075 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173076 for owners_file, patterns in to_check.iteritems():
3077 try:
3078 with file(owners_file) as f:
3079 lines = set(f.read().splitlines())
3080 for entry in patterns.itervalues():
3081 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3082 ]
3083 except IOError:
3084 # No OWNERS file, so all the rules are definitely missing.
3085 continue
3086
3087 # All the remaining lines weren't found in OWNERS files, so emit an error.
3088 errors = []
3089 for owners_file, patterns in to_check.iteritems():
3090 missing_lines = []
3091 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503092 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173093 missing_lines.extend(entry['rules'])
3094 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3095 if missing_lines:
3096 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053097 'Because of the presence of files:\n%s\n\n'
3098 '%s needs the following %d lines added:\n\n%s' %
3099 ('\n'.join(files), owners_file, len(missing_lines),
3100 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173101
3102 results = []
3103 if errors:
vabrf5ce3bf92016-07-11 14:52:413104 if input_api.is_committing:
3105 output = output_api.PresubmitError
3106 else:
3107 output = output_api.PresubmitPromptWarning
3108 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593109 'Found OWNERS files that need to be updated for IPC security ' +
3110 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173111 long_text='\n\n'.join(errors)))
3112
3113 return results
3114
3115
Robert Sesek2c905332020-05-06 23:17:133116def _GetFilesUsingSecurityCriticalFunctions(input_api):
3117 """Checks affected files for changes to security-critical calls. This
3118 function checks the full change diff, to catch both additions/changes
3119 and removals.
3120
3121 Returns a dict keyed by file name, and the value is a set of detected
3122 functions.
3123 """
3124 # Map of function pretty name (displayed in an error) to the pattern to
3125 # match it with.
3126 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373127 'content::GetServiceSandboxType<>()':
3128 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133129 }
3130 _PATTERNS_TO_CHECK = {
3131 k: input_api.re.compile(v)
3132 for k, v in _PATTERNS_TO_CHECK.items()
3133 }
3134
3135 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3136 files_to_functions = {}
3137 for f in input_api.AffectedFiles():
3138 diff = f.GenerateScmDiff()
3139 for line in diff.split('\n'):
3140 # Not using just RightHandSideLines() because removing a
3141 # call to a security-critical function can be just as important
3142 # as adding or changing the arguments.
3143 if line.startswith('-') or (line.startswith('+') and
3144 not line.startswith('++')):
3145 for name, pattern in _PATTERNS_TO_CHECK.items():
3146 if pattern.search(line):
3147 path = f.LocalPath()
3148 if not path in files_to_functions:
3149 files_to_functions[path] = set()
3150 files_to_functions[path].add(name)
3151 return files_to_functions
3152
3153
3154def _CheckSecurityChanges(input_api, output_api):
3155 """Checks that changes involving security-critical functions are reviewed
3156 by the security team.
3157 """
3158 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3159 if len(files_to_functions):
3160 owners_db = input_api.owners_db
3161 owner_email, reviewers = (
3162 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3163 input_api,
3164 owners_db.email_regexp,
3165 approval_needed=input_api.is_committing))
3166
3167 # Load the OWNERS file for security changes.
3168 owners_file = 'ipc/SECURITY_OWNERS'
3169 security_owners = owners_db.owners_rooted_at_file(owners_file)
3170
3171 has_security_owner = any([owner in reviewers for owner in security_owners])
3172 if not has_security_owner:
3173 msg = 'The following files change calls to security-sensive functions\n' \
3174 'that need to be reviewed by {}.\n'.format(owners_file)
3175 for path, names in files_to_functions.items():
3176 msg += ' {}\n'.format(path)
3177 for name in names:
3178 msg += ' {}\n'.format(name)
3179 msg += '\n'
3180
3181 if input_api.is_committing:
3182 output = output_api.PresubmitError
3183 else:
3184 output = output_api.PresubmitNotifyResult
3185 return [output(msg)]
3186
3187 return []
3188
3189
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263190def _CheckSetNoParent(input_api, output_api):
3191 """Checks that set noparent is only used together with an OWNERS file in
3192 //build/OWNERS.setnoparent (see also
3193 //docs/code_reviews.md#owners-files-details)
3194 """
3195 errors = []
3196
3197 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3198 allowed_owners_files = set()
3199 with open(allowed_owners_files_file, 'r') as f:
3200 for line in f:
3201 line = line.strip()
3202 if not line or line.startswith('#'):
3203 continue
3204 allowed_owners_files.add(line)
3205
3206 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3207
3208 for f in input_api.AffectedFiles(include_deletes=False):
3209 if not f.LocalPath().endswith('OWNERS'):
3210 continue
3211
3212 found_owners_files = set()
3213 found_set_noparent_lines = dict()
3214
3215 # Parse the OWNERS file.
3216 for lineno, line in enumerate(f.NewContents(), 1):
3217 line = line.strip()
3218 if line.startswith('set noparent'):
3219 found_set_noparent_lines[''] = lineno
3220 if line.startswith('file://'):
3221 if line in allowed_owners_files:
3222 found_owners_files.add('')
3223 if line.startswith('per-file'):
3224 match = per_file_pattern.match(line)
3225 if match:
3226 glob = match.group(1).strip()
3227 directive = match.group(2).strip()
3228 if directive == 'set noparent':
3229 found_set_noparent_lines[glob] = lineno
3230 if directive.startswith('file://'):
3231 if directive in allowed_owners_files:
3232 found_owners_files.add(glob)
3233
3234 # Check that every set noparent line has a corresponding file:// line
3235 # listed in build/OWNERS.setnoparent.
3236 for set_noparent_line in found_set_noparent_lines:
3237 if set_noparent_line in found_owners_files:
3238 continue
3239 errors.append(' %s:%d' % (f.LocalPath(),
3240 found_set_noparent_lines[set_noparent_line]))
3241
3242 results = []
3243 if errors:
3244 if input_api.is_committing:
3245 output = output_api.PresubmitError
3246 else:
3247 output = output_api.PresubmitPromptWarning
3248 results.append(output(
3249 'Found the following "set noparent" restrictions in OWNERS files that '
3250 'do not include owners from build/OWNERS.setnoparent:',
3251 long_text='\n\n'.join(errors)))
3252 return results
3253
3254
jbriance9e12f162016-11-25 07:57:503255def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313256 """Checks that added or removed lines in non third party affected
3257 header files do not lead to new useless class or struct forward
3258 declaration.
jbriance9e12f162016-11-25 07:57:503259 """
3260 results = []
3261 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3262 input_api.re.MULTILINE)
3263 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3264 input_api.re.MULTILINE)
3265 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313266 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193267 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493268 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313269 continue
3270
jbriance9e12f162016-11-25 07:57:503271 if not f.LocalPath().endswith('.h'):
3272 continue
3273
3274 contents = input_api.ReadFile(f)
3275 fwd_decls = input_api.re.findall(class_pattern, contents)
3276 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3277
3278 useless_fwd_decls = []
3279 for decl in fwd_decls:
3280 count = sum(1 for _ in input_api.re.finditer(
3281 r'\b%s\b' % input_api.re.escape(decl), contents))
3282 if count == 1:
3283 useless_fwd_decls.append(decl)
3284
3285 if not useless_fwd_decls:
3286 continue
3287
3288 for line in f.GenerateScmDiff().splitlines():
3289 if (line.startswith('-') and not line.startswith('--') or
3290 line.startswith('+') and not line.startswith('++')):
3291 for decl in useless_fwd_decls:
3292 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3293 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243294 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503295 (f.LocalPath(), decl)))
3296 useless_fwd_decls.remove(decl)
3297
3298 return results
3299
Jinsong Fan91ebbbd2019-04-16 14:57:173300def _CheckAndroidDebuggableBuild(input_api, output_api):
3301 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3302 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3303 this is a debuggable build of Android.
3304 """
3305 build_type_check_pattern = input_api.re.compile(
3306 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3307
3308 errors = []
3309
3310 sources = lambda affected_file: input_api.FilterSourceFile(
3311 affected_file,
3312 black_list=(_EXCLUDED_PATHS +
3313 _TEST_CODE_EXCLUDED_PATHS +
3314 input_api.DEFAULT_BLACK_LIST +
3315 (r"^android_webview[\\/]support_library[\\/]"
3316 "boundary_interfaces[\\/]",
3317 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3318 r'^third_party[\\/].*',
3319 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3320 r"webview[\\/]chromium[\\/]License.*",)),
3321 white_list=[r'.*\.java$'])
3322
3323 for f in input_api.AffectedSourceFiles(sources):
3324 for line_num, line in f.ChangedContents():
3325 if build_type_check_pattern.search(line):
3326 errors.append("%s:%d" % (f.LocalPath(), line_num))
3327
3328 results = []
3329
3330 if errors:
3331 results.append(output_api.PresubmitPromptWarning(
3332 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3333 ' Please use BuildInfo.isDebugAndroid() instead.',
3334 errors))
3335
3336 return results
jbriance9e12f162016-11-25 07:57:503337
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493338# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293339def _CheckAndroidToastUsage(input_api, output_api):
3340 """Checks that code uses org.chromium.ui.widget.Toast instead of
3341 android.widget.Toast (Chromium Toast doesn't force hardware
3342 acceleration on low-end devices, saving memory).
3343 """
3344 toast_import_pattern = input_api.re.compile(
3345 r'^import android\.widget\.Toast;$')
3346
3347 errors = []
3348
3349 sources = lambda affected_file: input_api.FilterSourceFile(
3350 affected_file,
3351 black_list=(_EXCLUDED_PATHS +
3352 _TEST_CODE_EXCLUDED_PATHS +
3353 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043354 (r'^chromecast[\\/].*',
3355 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493356 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293357
3358 for f in input_api.AffectedSourceFiles(sources):
3359 for line_num, line in f.ChangedContents():
3360 if toast_import_pattern.search(line):
3361 errors.append("%s:%d" % (f.LocalPath(), line_num))
3362
3363 results = []
3364
3365 if errors:
3366 results.append(output_api.PresubmitError(
3367 'android.widget.Toast usage is detected. Android toasts use hardware'
3368 ' acceleration, and can be\ncostly on low-end devices. Please use'
3369 ' org.chromium.ui.widget.Toast instead.\n'
3370 'Contact [email protected] if you have any questions.',
3371 errors))
3372
3373 return results
3374
3375
dgnaa68d5e2015-06-10 10:08:223376def _CheckAndroidCrLogUsage(input_api, output_api):
3377 """Checks that new logs using org.chromium.base.Log:
3378 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513379 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223380 """
pkotwicza1dd0b002016-05-16 14:41:043381
torne89540622017-03-24 19:41:303382 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043383 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303384 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043385 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303386 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043387 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3388 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093389 # The customtabs_benchmark is a small app that does not depend on Chromium
3390 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043391 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043392 ]
3393
dgnaa68d5e2015-06-10 10:08:223394 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123395 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3396 class_in_base_pattern = input_api.re.compile(
3397 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3398 has_some_log_import_pattern = input_api.re.compile(
3399 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223400 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553401 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223402 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463403 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553404 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223405
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463406 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493407 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043408 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123409
dgnaa68d5e2015-06-10 10:08:223410 tag_decl_errors = []
3411 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123412 tag_errors = []
dgn38736db2015-09-18 19:20:513413 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123414 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223415
3416 for f in input_api.AffectedSourceFiles(sources):
3417 file_content = input_api.ReadFile(f)
3418 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223419 # Per line checks
dgn87d9fb62015-06-12 09:15:123420 if (cr_log_import_pattern.search(file_content) or
3421 (class_in_base_pattern.search(file_content) and
3422 not has_some_log_import_pattern.search(file_content))):
3423 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223424 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553425 if rough_log_decl_pattern.search(line):
3426 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223427
3428 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123429 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223430 if match:
3431 has_modified_logs = True
3432
3433 # Make sure it uses "TAG"
3434 if not match.group('tag') == 'TAG':
3435 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123436 else:
3437 # Report non cr Log function calls in changed lines
3438 for line_num, line in f.ChangedContents():
3439 if log_call_pattern.search(line):
3440 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223441
3442 # Per file checks
3443 if has_modified_logs:
3444 # Make sure the tag is using the "cr" prefix and is not too long
3445 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513446 tag_name = match.group('name') if match else None
3447 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223448 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513449 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223450 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513451 elif '.' in tag_name:
3452 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223453
3454 results = []
3455 if tag_decl_errors:
3456 results.append(output_api.PresubmitPromptWarning(
3457 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513458 '"private static final String TAG = "<package tag>".\n'
3459 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223460 tag_decl_errors))
3461
3462 if tag_length_errors:
3463 results.append(output_api.PresubmitError(
3464 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513465 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223466 tag_length_errors))
3467
3468 if tag_errors:
3469 results.append(output_api.PresubmitPromptWarning(
3470 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3471 tag_errors))
3472
dgn87d9fb62015-06-12 09:15:123473 if util_log_errors:
dgn4401aa52015-04-29 16:26:173474 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123475 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3476 util_log_errors))
3477
dgn38736db2015-09-18 19:20:513478 if tag_with_dot_errors:
3479 results.append(output_api.PresubmitPromptWarning(
3480 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3481 tag_with_dot_errors))
3482
dgn4401aa52015-04-29 16:26:173483 return results
3484
3485
Yoland Yanb92fa522017-08-28 17:37:063486def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3487 """Checks that junit.framework.* is no longer used."""
3488 deprecated_junit_framework_pattern = input_api.re.compile(
3489 r'^import junit\.framework\..*;',
3490 input_api.re.MULTILINE)
3491 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493492 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063493 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133494 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063495 for line_num, line in f.ChangedContents():
3496 if deprecated_junit_framework_pattern.search(line):
3497 errors.append("%s:%d" % (f.LocalPath(), line_num))
3498
3499 results = []
3500 if errors:
3501 results.append(output_api.PresubmitError(
3502 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3503 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3504 ' if you have any question.', errors))
3505 return results
3506
3507
3508def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3509 """Checks that if new Java test classes have inheritance.
3510 Either the new test class is JUnit3 test or it is a JUnit4 test class
3511 with a base class, either case is undesirable.
3512 """
3513 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3514
3515 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493516 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063517 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133518 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063519 if not f.OldContents():
3520 class_declaration_start_flag = False
3521 for line_num, line in f.ChangedContents():
3522 if class_declaration_pattern.search(line):
3523 class_declaration_start_flag = True
3524 if class_declaration_start_flag and ' extends ' in line:
3525 errors.append('%s:%d' % (f.LocalPath(), line_num))
3526 if '{' in line:
3527 class_declaration_start_flag = False
3528
3529 results = []
3530 if errors:
3531 results.append(output_api.PresubmitPromptWarning(
3532 'The newly created files include Test classes that inherits from base'
3533 ' class. Please do not use inheritance in JUnit4 tests or add new'
3534 ' JUnit3 tests. Contact [email protected] if you have any'
3535 ' questions.', errors))
3536 return results
3537
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203538
yolandyan45001472016-12-21 21:12:423539def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3540 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3541 deprecated_annotation_import_pattern = input_api.re.compile(
3542 r'^import android\.test\.suitebuilder\.annotation\..*;',
3543 input_api.re.MULTILINE)
3544 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493545 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423546 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133547 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423548 for line_num, line in f.ChangedContents():
3549 if deprecated_annotation_import_pattern.search(line):
3550 errors.append("%s:%d" % (f.LocalPath(), line_num))
3551
3552 results = []
3553 if errors:
3554 results.append(output_api.PresubmitError(
3555 'Annotations in android.test.suitebuilder.annotation have been'
3556 ' deprecated since API level 24. Please use android.support.test.filters'
3557 ' from //third_party/android_support_test_runner:runner_java instead.'
3558 ' Contact [email protected] if you have any questions.', errors))
3559 return results
3560
3561
agrieve7b6479d82015-10-07 14:24:223562def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3563 """Checks if MDPI assets are placed in a correct directory."""
3564 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3565 ('/res/drawable/' in f.LocalPath() or
3566 '/res/drawable-ldrtl/' in f.LocalPath()))
3567 errors = []
3568 for f in input_api.AffectedFiles(include_deletes=False,
3569 file_filter=file_filter):
3570 errors.append(' %s' % f.LocalPath())
3571
3572 results = []
3573 if errors:
3574 results.append(output_api.PresubmitError(
3575 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3576 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3577 '/res/drawable-ldrtl/.\n'
3578 'Contact [email protected] if you have questions.', errors))
3579 return results
3580
3581
Nate Fischer535972b2017-09-16 01:06:183582def _CheckAndroidWebkitImports(input_api, output_api):
3583 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353584 android.webview.ValueCallback except in the WebView glue layer
3585 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183586 """
3587 valuecallback_import_pattern = input_api.re.compile(
3588 r'^import android\.webkit\.ValueCallback;$')
3589
3590 errors = []
3591
3592 sources = lambda affected_file: input_api.FilterSourceFile(
3593 affected_file,
3594 black_list=(_EXCLUDED_PATHS +
3595 _TEST_CODE_EXCLUDED_PATHS +
3596 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353597 (r'^android_webview[\\/]glue[\\/].*',
3598 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493599 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183600
3601 for f in input_api.AffectedSourceFiles(sources):
3602 for line_num, line in f.ChangedContents():
3603 if valuecallback_import_pattern.search(line):
3604 errors.append("%s:%d" % (f.LocalPath(), line_num))
3605
3606 results = []
3607
3608 if errors:
3609 results.append(output_api.PresubmitError(
3610 'android.webkit.ValueCallback usage is detected outside of the glue'
3611 ' layer. To stay compatible with the support library, android.webkit.*'
3612 ' classes should only be used inside the glue layer and'
3613 ' org.chromium.base.Callback should be used instead.',
3614 errors))
3615
3616 return results
3617
3618
Becky Zhou7c69b50992018-12-10 19:37:573619def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3620 """Checks Android XML styles """
3621 import sys
3622 original_sys_path = sys.path
3623 try:
3624 sys.path = sys.path + [input_api.os_path.join(
3625 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3626 import checkxmlstyle
3627 finally:
3628 # Restore sys.path to what it was before.
3629 sys.path = original_sys_path
3630
3631 if is_check_on_upload:
3632 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3633 else:
3634 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3635
3636
agrievef32bcc72016-04-04 14:57:403637class PydepsChecker(object):
3638 def __init__(self, input_api, pydeps_files):
3639 self._file_cache = {}
3640 self._input_api = input_api
3641 self._pydeps_files = pydeps_files
3642
3643 def _LoadFile(self, path):
3644 """Returns the list of paths within a .pydeps file relative to //."""
3645 if path not in self._file_cache:
3646 with open(path) as f:
3647 self._file_cache[path] = f.read()
3648 return self._file_cache[path]
3649
3650 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3651 """Returns an interable of paths within the .pydep, relativized to //."""
3652 os_path = self._input_api.os_path
3653 pydeps_dir = os_path.dirname(pydeps_path)
3654 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3655 if not l.startswith('*'))
3656 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3657
3658 def _CreateFilesToPydepsMap(self):
3659 """Returns a map of local_path -> list_of_pydeps."""
3660 ret = {}
3661 for pydep_local_path in self._pydeps_files:
3662 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3663 ret.setdefault(path, []).append(pydep_local_path)
3664 return ret
3665
3666 def ComputeAffectedPydeps(self):
3667 """Returns an iterable of .pydeps files that might need regenerating."""
3668 affected_pydeps = set()
3669 file_to_pydeps_map = None
3670 for f in self._input_api.AffectedFiles(include_deletes=True):
3671 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463672 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3673 # subrepositories. We can't figure out which files change, so re-check
3674 # all files.
3675 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383676 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3677 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403678 return self._pydeps_files
3679 elif local_path.endswith('.pydeps'):
3680 if local_path in self._pydeps_files:
3681 affected_pydeps.add(local_path)
3682 elif local_path.endswith('.py'):
3683 if file_to_pydeps_map is None:
3684 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3685 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3686 return affected_pydeps
3687
3688 def DetermineIfStale(self, pydeps_path):
3689 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413690 import difflib
John Budorick47ca3fe2018-02-10 00:53:103691 import os
3692
agrievef32bcc72016-04-04 14:57:403693 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033694 if old_pydeps_data:
3695 cmd = old_pydeps_data[1][1:].strip()
3696 old_contents = old_pydeps_data[2:]
3697 else:
3698 # A default cmd that should work in most cases (as long as pydeps filename
3699 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3700 # file is empty/new.
3701 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3702 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3703 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103704 env = dict(os.environ)
3705 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403706 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103707 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413708 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033709 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413710 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403711
3712
Tibor Goldschwendt360793f72019-06-25 18:23:493713def _ParseGclientArgs():
3714 args = {}
3715 with open('build/config/gclient_args.gni', 'r') as f:
3716 for line in f:
3717 line = line.strip()
3718 if not line or line.startswith('#'):
3719 continue
3720 attribute, value = line.split('=')
3721 args[attribute.strip()] = value.strip()
3722 return args
3723
3724
agrievef32bcc72016-04-04 14:57:403725def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3726 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403727 # This check is for Python dependency lists (.pydeps files), and involves
3728 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3729 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283730 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003731 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493732 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403733 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403734 results = []
3735 # First, check for new / deleted .pydeps.
3736 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033737 # Check whether we are running the presubmit check for a file in src.
3738 # f.LocalPath is relative to repo (src, or internal repo).
3739 # os_path.exists is relative to src repo.
3740 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3741 # to src and we can conclude that the pydeps is in src.
3742 if input_api.os_path.exists(f.LocalPath()):
3743 if f.LocalPath().endswith('.pydeps'):
3744 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3745 results.append(output_api.PresubmitError(
3746 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3747 'remove %s' % f.LocalPath()))
3748 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3749 results.append(output_api.PresubmitError(
3750 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3751 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403752
3753 if results:
3754 return results
3755
Mohamed Heikal7cd4d8312020-06-16 16:49:403756 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3757 affected_pydeps = set(checker.ComputeAffectedPydeps())
3758 affected_android_pydeps = affected_pydeps.intersection(
3759 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3760 if affected_android_pydeps and not is_android:
3761 results.append(output_api.PresubmitPromptOrNotify(
3762 'You have changed python files that may affect pydeps for android\n'
3763 'specific scripts. However, the relevant presumbit check cannot be\n'
3764 'run because you are not using an Android checkout. To validate that\n'
3765 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3766 'use the android-internal-presubmit optional trybot.\n'
3767 'Possibly stale pydeps files:\n{}'.format(
3768 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403769
Mohamed Heikal7cd4d8312020-06-16 16:49:403770 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3771 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403772 try:
phajdan.jr0d9878552016-11-04 10:49:413773 result = checker.DetermineIfStale(pydep_path)
3774 if result:
3775 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403776 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413777 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3778 'To regenerate, run:\n\n %s' %
3779 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403780 except input_api.subprocess.CalledProcessError as error:
3781 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3782 long_text=error.output)]
3783
3784 return results
3785
3786
glidere61efad2015-02-18 17:39:433787def _CheckSingletonInHeaders(input_api, output_api):
3788 """Checks to make sure no header files have |Singleton<|."""
3789 def FileFilter(affected_file):
3790 # It's ok for base/memory/singleton.h to have |Singleton<|.
3791 black_list = (_EXCLUDED_PATHS +
3792 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043793 (r"^base[\\/]memory[\\/]singleton\.h$",
3794 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473795 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433796 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3797
sergeyu34d21222015-09-16 00:11:443798 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433799 files = []
3800 for f in input_api.AffectedSourceFiles(FileFilter):
3801 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3802 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3803 contents = input_api.ReadFile(f)
3804 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243805 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433806 pattern.search(line)):
3807 files.append(f)
3808 break
3809
3810 if files:
yolandyandaabc6d2016-04-18 18:29:393811 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443812 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433813 'Please move them to an appropriate source file so that the ' +
3814 'template gets instantiated in a single compilation unit.',
3815 files) ]
3816 return []
3817
3818
[email protected]fd20b902014-05-09 02:14:533819_DEPRECATED_CSS = [
3820 # Values
3821 ( "-webkit-box", "flex" ),
3822 ( "-webkit-inline-box", "inline-flex" ),
3823 ( "-webkit-flex", "flex" ),
3824 ( "-webkit-inline-flex", "inline-flex" ),
3825 ( "-webkit-min-content", "min-content" ),
3826 ( "-webkit-max-content", "max-content" ),
3827
3828 # Properties
3829 ( "-webkit-background-clip", "background-clip" ),
3830 ( "-webkit-background-origin", "background-origin" ),
3831 ( "-webkit-background-size", "background-size" ),
3832 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443833 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533834
3835 # Functions
3836 ( "-webkit-gradient", "gradient" ),
3837 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3838 ( "-webkit-linear-gradient", "linear-gradient" ),
3839 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3840 ( "-webkit-radial-gradient", "radial-gradient" ),
3841 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3842]
3843
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203844
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493845# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243846def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533847 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253848 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343849 documentation and iOS CSS for dom distiller
3850 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253851 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533852 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493853 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253854 black_list = (_EXCLUDED_PATHS +
3855 _TEST_CODE_EXCLUDED_PATHS +
3856 input_api.DEFAULT_BLACK_LIST +
3857 (r"^chrome/common/extensions/docs",
3858 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343859 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443860 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253861 r"^native_client_sdk"))
3862 file_filter = lambda f: input_api.FilterSourceFile(
3863 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533864 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3865 for line_num, line in fpath.ChangedContents():
3866 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023867 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533868 results.append(output_api.PresubmitError(
3869 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3870 (fpath.LocalPath(), line_num, deprecated_value, value)))
3871 return results
3872
mohan.reddyf21db962014-10-16 12:26:473873
rlanday6802cf632017-05-30 17:48:363874def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363875 bad_files = {}
3876 for f in input_api.AffectedFiles(include_deletes=False):
3877 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493878 not f.LocalPath().startswith('third_party/blink') and
3879 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363880 continue
3881
Daniel Bratell65b033262019-04-23 08:17:063882 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363883 continue
3884
Vaclav Brozekd5de76a2018-03-17 07:57:503885 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363886 if "#include" in line and "../" in line]
3887 if not relative_includes:
3888 continue
3889 bad_files[f.LocalPath()] = relative_includes
3890
3891 if not bad_files:
3892 return []
3893
3894 error_descriptions = []
3895 for file_path, bad_lines in bad_files.iteritems():
3896 error_description = file_path
3897 for line in bad_lines:
3898 error_description += '\n ' + line
3899 error_descriptions.append(error_description)
3900
3901 results = []
3902 results.append(output_api.PresubmitError(
3903 'You added one or more relative #include paths (including "../").\n'
3904 'These shouldn\'t be used because they can be used to include headers\n'
3905 'from code that\'s not correctly specified as a dependency in the\n'
3906 'relevant BUILD.gn file(s).',
3907 error_descriptions))
3908
3909 return results
3910
Takeshi Yoshinoe387aa32017-08-02 13:16:133911
Daniel Bratell65b033262019-04-23 08:17:063912def _CheckForCcIncludes(input_api, output_api):
3913 """Check that nobody tries to include a cc file. It's a relatively
3914 common error which results in duplicate symbols in object
3915 files. This may not always break the build until someone later gets
3916 very confusing linking errors."""
3917 results = []
3918 for f in input_api.AffectedFiles(include_deletes=False):
3919 # We let third_party code do whatever it wants
3920 if (f.LocalPath().startswith('third_party') and
3921 not f.LocalPath().startswith('third_party/blink') and
3922 not f.LocalPath().startswith('third_party\\blink')):
3923 continue
3924
3925 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3926 continue
3927
3928 for _, line in f.ChangedContents():
3929 if line.startswith('#include "'):
3930 included_file = line.split('"')[1]
3931 if _IsCPlusPlusFile(input_api, included_file):
3932 # The most common naming for external files with C++ code,
3933 # apart from standard headers, is to call them foo.inc, but
3934 # Chromium sometimes uses foo-inc.cc so allow that as well.
3935 if not included_file.endswith(('.h', '-inc.cc')):
3936 results.append(output_api.PresubmitError(
3937 'Only header files or .inc files should be included in other\n'
3938 'C++ files. Compiling the contents of a cc file more than once\n'
3939 'will cause duplicate information in the build which may later\n'
3940 'result in strange link_errors.\n' +
3941 f.LocalPath() + ':\n ' +
3942 line))
3943
3944 return results
3945
3946
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203947def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3948 if not isinstance(key, ast.Str):
3949 return 'Key at line %d must be a string literal' % key.lineno
3950 if not isinstance(value, ast.Dict):
3951 return 'Value at line %d must be a dict' % value.lineno
3952 if len(value.keys) != 1:
3953 return 'Dict at line %d must have single entry' % value.lineno
3954 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3955 return (
3956 'Entry at line %d must have a string literal \'filepath\' as key' %
3957 value.lineno)
3958 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133959
Takeshi Yoshinoe387aa32017-08-02 13:16:133960
Sergey Ulanov4af16052018-11-08 02:41:463961def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962 if not isinstance(key, ast.Str):
3963 return 'Key at line %d must be a string literal' % key.lineno
3964 if not isinstance(value, ast.List):
3965 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463966 for element in value.elts:
3967 if not isinstance(element, ast.Str):
3968 return 'Watchlist elements on line %d is not a string' % key.lineno
3969 if not email_regex.match(element.s):
3970 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3971 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203972 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133973
Takeshi Yoshinoe387aa32017-08-02 13:16:133974
Sergey Ulanov4af16052018-11-08 02:41:463975def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976 mismatch_template = (
3977 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3978 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133979
Sergey Ulanov4af16052018-11-08 02:41:463980 email_regex = input_api.re.compile(
3981 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3982
3983 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203984 i = 0
3985 last_key = ''
3986 while True:
3987 if i >= len(wd_dict.keys):
3988 if i >= len(w_dict.keys):
3989 return None
3990 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3991 elif i >= len(w_dict.keys):
3992 return (
3993 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133994
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995 wd_key = wd_dict.keys[i]
3996 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133997
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203998 result = _CheckWatchlistDefinitionsEntrySyntax(
3999 wd_key, wd_dict.values[i], ast)
4000 if result is not None:
4001 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134002
Sergey Ulanov4af16052018-11-08 02:41:464003 result = _CheckWatchlistsEntrySyntax(
4004 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204005 if result is not None:
4006 return 'Bad entry in WATCHLISTS dict: %s' % result
4007
4008 if wd_key.s != w_key.s:
4009 return mismatch_template % (
4010 '%s at line %d' % (wd_key.s, wd_key.lineno),
4011 '%s at line %d' % (w_key.s, w_key.lineno))
4012
4013 if wd_key.s < last_key:
4014 return (
4015 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4016 (wd_key.lineno, w_key.lineno))
4017 last_key = wd_key.s
4018
4019 i = i + 1
4020
4021
Sergey Ulanov4af16052018-11-08 02:41:464022def _CheckWATCHLISTSSyntax(expression, input_api):
4023 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204024 if not isinstance(expression, ast.Expression):
4025 return 'WATCHLISTS file must contain a valid expression'
4026 dictionary = expression.body
4027 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4028 return 'WATCHLISTS file must have single dict with exactly two entries'
4029
4030 first_key = dictionary.keys[0]
4031 first_value = dictionary.values[0]
4032 second_key = dictionary.keys[1]
4033 second_value = dictionary.values[1]
4034
4035 if (not isinstance(first_key, ast.Str) or
4036 first_key.s != 'WATCHLIST_DEFINITIONS' or
4037 not isinstance(first_value, ast.Dict)):
4038 return (
4039 'The first entry of the dict in WATCHLISTS file must be '
4040 'WATCHLIST_DEFINITIONS dict')
4041
4042 if (not isinstance(second_key, ast.Str) or
4043 second_key.s != 'WATCHLISTS' or
4044 not isinstance(second_value, ast.Dict)):
4045 return (
4046 'The second entry of the dict in WATCHLISTS file must be '
4047 'WATCHLISTS dict')
4048
Sergey Ulanov4af16052018-11-08 02:41:464049 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134050
4051
4052def _CheckWATCHLISTS(input_api, output_api):
4053 for f in input_api.AffectedFiles(include_deletes=False):
4054 if f.LocalPath() == 'WATCHLISTS':
4055 contents = input_api.ReadFile(f, 'r')
4056
4057 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204058 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134059 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204060 # Get an AST tree for it and scan the tree for detailed style checking.
4061 expression = input_api.ast.parse(
4062 contents, filename='WATCHLISTS', mode='eval')
4063 except ValueError as e:
4064 return [output_api.PresubmitError(
4065 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4066 except SyntaxError as e:
4067 return [output_api.PresubmitError(
4068 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4069 except TypeError as e:
4070 return [output_api.PresubmitError(
4071 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134072
Sergey Ulanov4af16052018-11-08 02:41:464073 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204074 if result is not None:
4075 return [output_api.PresubmitError(result)]
4076 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134077
4078 return []
4079
4080
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194081def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4082 """Checks that newly added header files have corresponding GN changes.
4083 Note that this is only a heuristic. To be precise, run script:
4084 build/check_gn_headers.py.
4085 """
4086
4087 def headers(f):
4088 return input_api.FilterSourceFile(
4089 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4090
4091 new_headers = []
4092 for f in input_api.AffectedSourceFiles(headers):
4093 if f.Action() != 'A':
4094 continue
4095 new_headers.append(f.LocalPath())
4096
4097 def gn_files(f):
4098 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4099
4100 all_gn_changed_contents = ''
4101 for f in input_api.AffectedSourceFiles(gn_files):
4102 for _, line in f.ChangedContents():
4103 all_gn_changed_contents += line
4104
4105 problems = []
4106 for header in new_headers:
4107 basename = input_api.os_path.basename(header)
4108 if basename not in all_gn_changed_contents:
4109 problems.append(header)
4110
4111 if problems:
4112 return [output_api.PresubmitPromptWarning(
4113 'Missing GN changes for new header files', items=sorted(problems),
4114 long_text='Please double check whether newly added header files need '
4115 'corresponding changes in gn or gni files.\nThis checking is only a '
4116 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4117 'Read https://crbug.com/661774 for more info.')]
4118 return []
4119
4120
Michael Giuffridad3bc8672018-10-25 22:48:024121def _CheckCorrectProductNameInMessages(input_api, output_api):
4122 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4123
4124 This assumes we won't intentionally reference one product from the other
4125 product.
4126 """
4127 all_problems = []
4128 test_cases = [{
4129 "filename_postfix": "google_chrome_strings.grd",
4130 "correct_name": "Chrome",
4131 "incorrect_name": "Chromium",
4132 }, {
4133 "filename_postfix": "chromium_strings.grd",
4134 "correct_name": "Chromium",
4135 "incorrect_name": "Chrome",
4136 }]
4137
4138 for test_case in test_cases:
4139 problems = []
4140 filename_filter = lambda x: x.LocalPath().endswith(
4141 test_case["filename_postfix"])
4142
4143 # Check each new line. Can yield false positives in multiline comments, but
4144 # easier than trying to parse the XML because messages can have nested
4145 # children, and associating message elements with affected lines is hard.
4146 for f in input_api.AffectedSourceFiles(filename_filter):
4147 for line_num, line in f.ChangedContents():
4148 if "<message" in line or "<!--" in line or "-->" in line:
4149 continue
4150 if test_case["incorrect_name"] in line:
4151 problems.append(
4152 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4153
4154 if problems:
4155 message = (
4156 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4157 % (test_case["correct_name"], test_case["correct_name"],
4158 test_case["incorrect_name"]))
4159 all_problems.append(
4160 output_api.PresubmitPromptWarning(message, items=problems))
4161
4162 return all_problems
4163
4164
Dirk Pranke3c18a382019-03-15 01:07:514165def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4166 # TODO(crbug.com/941824): We need to make sure the entries in
4167 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4168 # so that users of //buildtools in other projects get the same tooling
4169 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4170 # support to gclient, we can eliminate the duplication and delete
4171 # this presubmit check.
4172
4173 # Update this regexp if new revisions are added to the files.
4174 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264175 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514176
4177 # If a user is changing one revision, they need to change the same
4178 # line in both files. This means that any given change should contain
4179 # exactly the same list of changed lines that match the regexps. The
4180 # replace(' ', '') call allows us to ignore whitespace changes to the
4181 # lines. The 'long_text' parameter to the error will contain the
4182 # list of changed lines in both files, which should make it easy enough
4183 # to spot the error without going overboard in this implementation.
4184 revs_changes = {
4185 'DEPS': {},
4186 'buildtools/DEPS': {},
4187 }
4188 long_text = ''
4189
4190 for f in input_api.AffectedFiles(
4191 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4192 for line_num, line in f.ChangedContents():
4193 if rev_regexp.search(line):
4194 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4195 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4196
4197 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4198 return [output_api.PresubmitError(
4199 'Change buildtools revisions in sync in both //DEPS and '
4200 '//buildtools/DEPS.', long_text=long_text + '\n')]
4201 else:
4202 return []
4203
4204
Daniel Bratell93eb6c62019-04-29 20:13:364205def _CheckForTooLargeFiles(input_api, output_api):
4206 """Avoid large files, especially binary files, in the repository since
4207 git doesn't scale well for those. They will be in everyone's repo
4208 clones forever, forever making Chromium slower to clone and work
4209 with."""
4210
4211 # Uploading files to cloud storage is not trivial so we don't want
4212 # to set the limit too low, but the upper limit for "normal" large
4213 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4214 # anything over 20 MB is exceptional.
4215 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4216
4217 too_large_files = []
4218 for f in input_api.AffectedFiles():
4219 # Check both added and modified files (but not deleted files).
4220 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384221 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364222 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4223 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4224
4225 if too_large_files:
4226 message = (
4227 'Do not commit large files to git since git scales badly for those.\n' +
4228 'Instead put the large files in cloud storage and use DEPS to\n' +
4229 'fetch them.\n' + '\n'.join(too_large_files)
4230 )
4231 return [output_api.PresubmitError(
4232 'Too large files found in commit', long_text=message + '\n')]
4233 else:
4234 return []
4235
Max Morozb47503b2019-08-08 21:03:274236
4237def _CheckFuzzTargets(input_api, output_api):
4238 """Checks specific for fuzz target sources."""
4239 EXPORTED_SYMBOLS = [
4240 'LLVMFuzzerInitialize',
4241 'LLVMFuzzerCustomMutator',
4242 'LLVMFuzzerCustomCrossOver',
4243 'LLVMFuzzerMutate',
4244 ]
4245
4246 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4247
4248 def FilterFile(affected_file):
4249 """Ignore libFuzzer source code."""
4250 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4251 black_list = r"^third_party[\\/]libFuzzer"
4252
4253 return input_api.FilterSourceFile(
4254 affected_file,
4255 white_list=[white_list],
4256 black_list=[black_list])
4257
4258 files_with_missing_header = []
4259 for f in input_api.AffectedSourceFiles(FilterFile):
4260 contents = input_api.ReadFile(f, 'r')
4261 if REQUIRED_HEADER in contents:
4262 continue
4263
4264 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4265 files_with_missing_header.append(f.LocalPath())
4266
4267 if not files_with_missing_header:
4268 return []
4269
4270 long_text = (
4271 'If you define any of the libFuzzer optional functions (%s), it is '
4272 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4273 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4274 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4275 'to access command line arguments passed to the fuzzer. Instead, prefer '
4276 'static initialization and shared resources as documented in '
4277 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4278 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4279 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4280 )
4281
4282 return [output_api.PresubmitPromptWarning(
4283 message="Missing '%s' in:" % REQUIRED_HEADER,
4284 items=files_with_missing_header,
4285 long_text=long_text)]
4286
4287
Mohamed Heikald048240a2019-11-12 16:57:374288def _CheckNewImagesWarning(input_api, output_api):
4289 """
4290 Warns authors who add images into the repo to make sure their images are
4291 optimized before committing.
4292 """
4293 images_added = False
4294 image_paths = []
4295 errors = []
4296 filter_lambda = lambda x: input_api.FilterSourceFile(
4297 x,
4298 black_list=(('(?i).*test', r'.*\/junit\/')
4299 + input_api.DEFAULT_BLACK_LIST),
4300 white_list=[r'.*\/(drawable|mipmap)' ]
4301 )
4302 for f in input_api.AffectedFiles(
4303 include_deletes=False, file_filter=filter_lambda):
4304 local_path = f.LocalPath().lower()
4305 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4306 images_added = True
4307 image_paths.append(f)
4308 if images_added:
4309 errors.append(output_api.PresubmitPromptWarning(
4310 'It looks like you are trying to commit some images. If these are '
4311 'non-test-only images, please make sure to read and apply the tips in '
4312 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4313 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4314 'FYI only and will not block your CL on the CQ.', image_paths))
4315 return errors
4316
4317
dgnaa68d5e2015-06-10 10:08:224318def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574319 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224320 results = []
dgnaa68d5e2015-06-10 10:08:224321 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174322 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224323 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294324 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064325 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4326 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424327 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184328 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574329 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374330 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154331 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574332 return results
4333
4334def _AndroidSpecificOnCommitChecks(input_api, output_api):
4335 """Groups commit checks that target android code."""
4336 results = []
4337 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224338 return results
4339
Chris Hall59f8d0c72020-05-01 07:31:194340# TODO(chrishall): could we additionally match on any path owned by
4341# ui/accessibility/OWNERS ?
4342_ACCESSIBILITY_PATHS = (
4343 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4344 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4345 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4346 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4347 r"^content[\\/]browser[\\/]accessibility[\\/]",
4348 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4349 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4350 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4351 r"^ui[\\/]accessibility[\\/]",
4352 r"^ui[\\/]views[\\/]accessibility[\\/]",
4353)
4354
4355def _CheckAccessibilityRelnotesField(input_api, output_api):
4356 """Checks that commits to accessibility code contain an AX-Relnotes field in
4357 their commit message."""
4358 def FileFilter(affected_file):
4359 paths = _ACCESSIBILITY_PATHS
4360 return input_api.FilterSourceFile(affected_file, white_list=paths)
4361
4362 # Only consider changes affecting accessibility paths.
4363 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4364 return []
4365
Akihiro Ota08108e542020-05-20 15:30:534366 # AX-Relnotes can appear in either the description or the footer.
4367 # When searching the description, require 'AX-Relnotes:' to appear at the
4368 # beginning of a line.
4369 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4370 description_has_relnotes = any(ax_regex.match(line)
4371 for line in input_api.change.DescriptionText().lower().splitlines())
4372
4373 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4374 'AX-Relnotes', [])
4375 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194376 return []
4377
4378 # TODO(chrishall): link to Relnotes documentation in message.
4379 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4380 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4381 "user-facing changes"
4382 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4383 "user-facing effects"
4384 "\n if this is confusing or annoying then please contact members "
4385 "of ui/accessibility/OWNERS.")
4386
4387 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224388
[email protected]22c9bd72011-03-27 16:47:394389def _CommonChecks(input_api, output_api):
4390 """Checks common to both upload and commit."""
4391 results = []
4392 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384393 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544394 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084395
4396 author = input_api.change.author_email
4397 if author and author not in _KNOWN_ROBOTS:
4398 results.extend(
4399 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4400
Chris Hall59f8d0c72020-05-01 07:31:194401 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194402 results.extend(
[email protected]760deea2013-12-10 19:33:494403 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234404 results.extend(
4405 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544406 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184407 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344408 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524409 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224410 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444411 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594412 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314413 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064414 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124415 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184416 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224417 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304418 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494419 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034420 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494421 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444422 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294423 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274424 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074425 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544426 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444427 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394428 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554429 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044430 results.extend(
4431 input_api.canned_checks.CheckChangeHasNoTabs(
4432 input_api,
4433 output_api,
4434 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404435 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164436 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084437 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244438 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474439 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044440 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054441 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144442 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234443 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434444 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404445 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154446 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034447 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134448 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264449 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504450 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364451 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064452 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134453 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434454 results.extend(input_api.RunTests(
4455 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264456 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124457 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024458 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514459 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364460 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004461 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514462 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244463
Vaclav Brozekcdc7defb2018-03-20 09:54:354464 for f in input_api.AffectedFiles():
4465 path, name = input_api.os_path.split(f.LocalPath())
4466 if name == 'PRESUBMIT.py':
4467 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004468 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4469 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074470 # The PRESUBMIT.py file (and the directory containing it) might
4471 # have been affected by being moved or removed, so only try to
4472 # run the tests if they still exist.
4473 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4474 input_api, output_api, full_path,
4475 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394476 return results
[email protected]1f7b4172010-01-28 01:17:344477
[email protected]b337cb5b2011-01-23 21:24:054478
[email protected]b8079ae4a2012-12-05 19:56:494479def _CheckPatchFiles(input_api, output_api):
4480 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4481 if f.LocalPath().endswith(('.orig', '.rej'))]
4482 if problems:
4483 return [output_api.PresubmitError(
4484 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034485 else:
4486 return []
[email protected]b8079ae4a2012-12-05 19:56:494487
4488
Kent Tamura5a8755d2017-06-29 23:37:074489def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214490 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4491 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4492 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074493 include_re = input_api.re.compile(
4494 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4495 extension_re = input_api.re.compile(r'\.[a-z]+$')
4496 errors = []
4497 for f in input_api.AffectedFiles():
4498 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4499 continue
4500 found_line_number = None
4501 found_macro = None
4502 for line_num, line in f.ChangedContents():
4503 match = macro_re.search(line)
4504 if match:
4505 found_line_number = line_num
4506 found_macro = match.group(2)
4507 break
4508 if not found_line_number:
4509 continue
4510
4511 found_include = False
4512 for line in f.NewContents():
4513 if include_re.search(line):
4514 found_include = True
4515 break
4516 if found_include:
4517 continue
4518
4519 if not f.LocalPath().endswith('.h'):
4520 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4521 try:
4522 content = input_api.ReadFile(primary_header_path, 'r')
4523 if include_re.search(content):
4524 continue
4525 except IOError:
4526 pass
4527 errors.append('%s:%d %s macro is used without including build/'
4528 'build_config.h.'
4529 % (f.LocalPath(), found_line_number, found_macro))
4530 if errors:
4531 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4532 return []
4533
4534
[email protected]b00342e7f2013-03-26 16:21:544535def _DidYouMeanOSMacro(bad_macro):
4536 try:
4537 return {'A': 'OS_ANDROID',
4538 'B': 'OS_BSD',
4539 'C': 'OS_CHROMEOS',
4540 'F': 'OS_FREEBSD',
4541 'L': 'OS_LINUX',
4542 'M': 'OS_MACOSX',
4543 'N': 'OS_NACL',
4544 'O': 'OS_OPENBSD',
4545 'P': 'OS_POSIX',
4546 'S': 'OS_SOLARIS',
4547 'W': 'OS_WIN'}[bad_macro[3].upper()]
4548 except KeyError:
4549 return ''
4550
4551
4552def _CheckForInvalidOSMacrosInFile(input_api, f):
4553 """Check for sensible looking, totally invalid OS macros."""
4554 preprocessor_statement = input_api.re.compile(r'^\s*#')
4555 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4556 results = []
4557 for lnum, line in f.ChangedContents():
4558 if preprocessor_statement.search(line):
4559 for match in os_macro.finditer(line):
4560 if not match.group(1) in _VALID_OS_MACROS:
4561 good = _DidYouMeanOSMacro(match.group(1))
4562 did_you_mean = ' (did you mean %s?)' % good if good else ''
4563 results.append(' %s:%d %s%s' % (f.LocalPath(),
4564 lnum,
4565 match.group(1),
4566 did_you_mean))
4567 return results
4568
4569
4570def _CheckForInvalidOSMacros(input_api, output_api):
4571 """Check all affected files for invalid OS macros."""
4572 bad_macros = []
tzik3f295992018-12-04 20:32:234573 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474574 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544575 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4576
4577 if not bad_macros:
4578 return []
4579
4580 return [output_api.PresubmitError(
4581 'Possibly invalid OS macro[s] found. Please fix your code\n'
4582 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4583
lliabraa35bab3932014-10-01 12:16:444584
4585def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4586 """Check all affected files for invalid "if defined" macros."""
4587 ALWAYS_DEFINED_MACROS = (
4588 "TARGET_CPU_PPC",
4589 "TARGET_CPU_PPC64",
4590 "TARGET_CPU_68K",
4591 "TARGET_CPU_X86",
4592 "TARGET_CPU_ARM",
4593 "TARGET_CPU_MIPS",
4594 "TARGET_CPU_SPARC",
4595 "TARGET_CPU_ALPHA",
4596 "TARGET_IPHONE_SIMULATOR",
4597 "TARGET_OS_EMBEDDED",
4598 "TARGET_OS_IPHONE",
4599 "TARGET_OS_MAC",
4600 "TARGET_OS_UNIX",
4601 "TARGET_OS_WIN32",
4602 )
4603 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4604 results = []
4605 for lnum, line in f.ChangedContents():
4606 for match in ifdef_macro.finditer(line):
4607 if match.group(1) in ALWAYS_DEFINED_MACROS:
4608 always_defined = ' %s is always defined. ' % match.group(1)
4609 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4610 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4611 lnum,
4612 always_defined,
4613 did_you_mean))
4614 return results
4615
4616
4617def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4618 """Check all affected files for invalid "if defined" macros."""
4619 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054620 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444621 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054622 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214623 continue
lliabraa35bab3932014-10-01 12:16:444624 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4625 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4626
4627 if not bad_macros:
4628 return []
4629
4630 return [output_api.PresubmitError(
4631 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4632 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4633 bad_macros)]
4634
4635
mlamouria82272622014-09-16 18:45:044636def _CheckForIPCRules(input_api, output_api):
4637 """Check for same IPC rules described in
4638 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4639 """
4640 base_pattern = r'IPC_ENUM_TRAITS\('
4641 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4642 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4643
4644 problems = []
4645 for f in input_api.AffectedSourceFiles(None):
4646 local_path = f.LocalPath()
4647 if not local_path.endswith('.h'):
4648 continue
4649 for line_number, line in f.ChangedContents():
4650 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4651 problems.append(
4652 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4653
4654 if problems:
4655 return [output_api.PresubmitPromptWarning(
4656 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4657 else:
4658 return []
4659
[email protected]b00342e7f2013-03-26 16:21:544660
Stephen Martinis97a394142018-06-07 23:06:054661def _CheckForLongPathnames(input_api, output_api):
4662 """Check to make sure no files being submitted have long paths.
4663 This causes issues on Windows.
4664 """
4665 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194666 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054667 local_path = f.LocalPath()
4668 # Windows has a path limit of 260 characters. Limit path length to 200 so
4669 # that we have some extra for the prefix on dev machines and the bots.
4670 if len(local_path) > 200:
4671 problems.append(local_path)
4672
4673 if problems:
4674 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4675 else:
4676 return []
4677
4678
Daniel Bratell8ba52722018-03-02 16:06:144679def _CheckForIncludeGuards(input_api, output_api):
4680 """Check that header files have proper guards against multiple inclusion.
4681 If a file should not have such guards (and it probably should) then it
4682 should include the string "no-include-guard-because-multiply-included".
4683 """
Daniel Bratell6a75baef62018-06-04 10:04:454684 def is_chromium_header_file(f):
4685 # We only check header files under the control of the Chromium
4686 # project. That is, those outside third_party apart from
4687 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324688 # We also exclude *_message_generator.h headers as they use
4689 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454690 file_with_path = input_api.os_path.normpath(f.LocalPath())
4691 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324692 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454693 (not file_with_path.startswith('third_party') or
4694 file_with_path.startswith(
4695 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144696
4697 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344698 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144699
4700 errors = []
4701
Daniel Bratell6a75baef62018-06-04 10:04:454702 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144703 guard_name = None
4704 guard_line_number = None
4705 seen_guard_end = False
4706
4707 file_with_path = input_api.os_path.normpath(f.LocalPath())
4708 base_file_name = input_api.os_path.splitext(
4709 input_api.os_path.basename(file_with_path))[0]
4710 upper_base_file_name = base_file_name.upper()
4711
4712 expected_guard = replace_special_with_underscore(
4713 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144714
4715 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574716 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4717 # are too many (1000+) files with slight deviations from the
4718 # coding style. The most important part is that the include guard
4719 # is there, and that it's unique, not the name so this check is
4720 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144721 #
4722 # As code becomes more uniform, this could be made stricter.
4723
4724 guard_name_pattern_list = [
4725 # Anything with the right suffix (maybe with an extra _).
4726 r'\w+_H__?',
4727
Daniel Bratell39b5b062018-05-16 18:09:574728 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144729 r'\w+_h',
4730
4731 # Anything including the uppercase name of the file.
4732 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4733 upper_base_file_name)) + r'\w*',
4734 ]
4735 guard_name_pattern = '|'.join(guard_name_pattern_list)
4736 guard_pattern = input_api.re.compile(
4737 r'#ifndef\s+(' + guard_name_pattern + ')')
4738
4739 for line_number, line in enumerate(f.NewContents()):
4740 if 'no-include-guard-because-multiply-included' in line:
4741 guard_name = 'DUMMY' # To not trigger check outside the loop.
4742 break
4743
4744 if guard_name is None:
4745 match = guard_pattern.match(line)
4746 if match:
4747 guard_name = match.group(1)
4748 guard_line_number = line_number
4749
Daniel Bratell39b5b062018-05-16 18:09:574750 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454751 # don't match the chromium style guide, but new files should
4752 # get it right.
4753 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574754 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144755 errors.append(output_api.PresubmitPromptWarning(
4756 'Header using the wrong include guard name %s' % guard_name,
4757 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574758 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144759 else:
4760 # The line after #ifndef should have a #define of the same name.
4761 if line_number == guard_line_number + 1:
4762 expected_line = '#define %s' % guard_name
4763 if line != expected_line:
4764 errors.append(output_api.PresubmitPromptWarning(
4765 'Missing "%s" for include guard' % expected_line,
4766 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4767 'Expected: %r\nGot: %r' % (expected_line, line)))
4768
4769 if not seen_guard_end and line == '#endif // %s' % guard_name:
4770 seen_guard_end = True
4771 elif seen_guard_end:
4772 if line.strip() != '':
4773 errors.append(output_api.PresubmitPromptWarning(
4774 'Include guard %s not covering the whole file' % (
4775 guard_name), [f.LocalPath()]))
4776 break # Nothing else to check and enough to warn once.
4777
4778 if guard_name is None:
4779 errors.append(output_api.PresubmitPromptWarning(
4780 'Missing include guard %s' % expected_guard,
4781 [f.LocalPath()],
4782 'Missing include guard in %s\n'
4783 'Recommended name: %s\n'
4784 'This check can be disabled by having the string\n'
4785 'no-include-guard-because-multiply-included in the header.' %
4786 (f.LocalPath(), expected_guard)))
4787
4788 return errors
4789
4790
mostynbb639aca52015-01-07 20:31:234791def _CheckForWindowsLineEndings(input_api, output_api):
4792 """Check source code and known ascii text files for Windows style line
4793 endings.
4794 """
earthdok1b5e0ee2015-03-10 15:19:104795 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234796
4797 file_inclusion_pattern = (
4798 known_text_files,
4799 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4800 )
4801
mostynbb639aca52015-01-07 20:31:234802 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534803 source_file_filter = lambda f: input_api.FilterSourceFile(
4804 f, white_list=file_inclusion_pattern, black_list=None)
4805 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504806 include_file = False
4807 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234808 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504809 include_file = True
4810 if include_file:
4811 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234812
4813 if problems:
4814 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4815 'these files to contain Windows style line endings?\n' +
4816 '\n'.join(problems))]
4817
4818 return []
4819
4820
Vaclav Brozekd5de76a2018-03-17 07:57:504821def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134822 """Checks that all source files use SYSLOG properly."""
4823 syslog_files = []
4824 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564825 for line_number, line in f.ChangedContents():
4826 if 'SYSLOG' in line:
4827 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4828
pastarmovj89f7ee12016-09-20 14:58:134829 if syslog_files:
4830 return [output_api.PresubmitPromptWarning(
4831 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4832 ' calls.\nFiles to check:\n', items=syslog_files)]
4833 return []
4834
4835
[email protected]1f7b4172010-01-28 01:17:344836def CheckChangeOnUpload(input_api, output_api):
4837 results = []
4838 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474839 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284840 results.extend(
jam93a6ee792017-02-08 23:59:224841 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194842 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224843 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134844 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164845 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534846 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194847 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274848 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544849 return results
[email protected]ca8d1982009-02-19 16:33:124850
4851
[email protected]1bfb8322014-04-23 01:02:414852def GetTryServerMasterForBot(bot):
4853 """Returns the Try Server master for the given bot.
4854
[email protected]0bb112362014-07-26 04:38:324855 It tries to guess the master from the bot name, but may still fail
4856 and return None. There is no longer a default master.
4857 """
4858 # Potentially ambiguous bot names are listed explicitly.
4859 master_map = {
tandriie5587792016-07-14 00:34:504860 'chromium_presubmit': 'master.tryserver.chromium.linux',
4861 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414862 }
[email protected]0bb112362014-07-26 04:38:324863 master = master_map.get(bot)
4864 if not master:
wnwen4fbaab82016-05-25 12:54:364865 if 'android' in bot:
tandriie5587792016-07-14 00:34:504866 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364867 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504868 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324869 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504870 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324871 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504872 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324873 return master
[email protected]1bfb8322014-04-23 01:02:414874
4875
[email protected]ca8d1982009-02-19 16:33:124876def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544877 results = []
[email protected]1f7b4172010-01-28 01:17:344878 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574879 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544880 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274881 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344882 input_api,
4883 output_api,
[email protected]2fdd1f362013-01-16 03:56:034884 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274885
jam93a6ee792017-02-08 23:59:224886 results.extend(
4887 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544888 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4889 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384890 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4891 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414892 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4893 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544894 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144895
4896
Rainhard Findlingfc31844c52020-05-15 09:58:264897def _CheckStrings(input_api, output_api):
4898 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024899 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4900 # footer is set to true.
4901 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264902 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024903 footer.lower()
4904 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264905 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024906
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144907 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264908 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144909 import sys
4910 from io import StringIO
4911
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144912 new_or_added_paths = set(f.LocalPath()
4913 for f in input_api.AffectedFiles()
4914 if (f.Action() == 'A' or f.Action() == 'M'))
4915 removed_paths = set(f.LocalPath()
4916 for f in input_api.AffectedFiles(include_deletes=True)
4917 if f.Action() == 'D')
4918
4919 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264920 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164921 if not affected_grds:
4922 return []
4923
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144924 affected_png_paths = [f.AbsoluteLocalPath()
4925 for f in input_api.AffectedFiles()
4926 if (f.LocalPath().endswith('.png'))]
4927
4928 # Check for screenshots. Developers can upload screenshots using
4929 # tools/translation/upload_screenshots.py which finds and uploads
4930 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4931 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4932 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4933 #
4934 # The logic here is as follows:
4935 #
4936 # - If the CL has a .png file under the screenshots directory for a grd
4937 # file, warn the developer. Actual images should never be checked into the
4938 # Chrome repo.
4939 #
4940 # - If the CL contains modified or new messages in grd files and doesn't
4941 # contain the corresponding .sha1 files, warn the developer to add images
4942 # and upload them via tools/translation/upload_screenshots.py.
4943 #
4944 # - If the CL contains modified or new messages in grd files and the
4945 # corresponding .sha1 files, everything looks good.
4946 #
4947 # - If the CL contains removed messages in grd files but the corresponding
4948 # .sha1 files aren't removed, warn the developer to remove them.
4949 unnecessary_screenshots = []
4950 missing_sha1 = []
4951 unnecessary_sha1_files = []
4952
Rainhard Findlingfc31844c52020-05-15 09:58:264953 # This checks verifies that the ICU syntax of messages this CL touched is
4954 # valid, and reports any found syntax errors.
4955 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4956 # without developers being aware of them. Later on, such ICU syntax errors
4957 # break message extraction for translation, hence would block Chromium
4958 # translations until they are fixed.
4959 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144960
4961 def _CheckScreenshotAdded(screenshots_dir, message_id):
4962 sha1_path = input_api.os_path.join(
4963 screenshots_dir, message_id + '.png.sha1')
4964 if sha1_path not in new_or_added_paths:
4965 missing_sha1.append(sha1_path)
4966
4967
4968 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4969 sha1_path = input_api.os_path.join(
4970 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034971 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144972 unnecessary_sha1_files.append(sha1_path)
4973
Rainhard Findlingfc31844c52020-05-15 09:58:264974
4975 def _ValidateIcuSyntax(text, level, signatures):
4976 """Validates ICU syntax of a text string.
4977
4978 Check if text looks similar to ICU and checks for ICU syntax correctness
4979 in this case. Reports various issues with ICU syntax and values of
4980 variants. Supports checking of nested messages. Accumulate information of
4981 each ICU messages found in the text for further checking.
4982
4983 Args:
4984 text: a string to check.
4985 level: a number of current nesting level.
4986 signatures: an accumulator, a list of tuple of (level, variable,
4987 kind, variants).
4988
4989 Returns:
4990 None if a string is not ICU or no issue detected.
4991 A tuple of (message, start index, end index) if an issue detected.
4992 """
4993 valid_types = {
4994 'plural': (frozenset(
4995 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4996 frozenset(['=1', 'other'])),
4997 'selectordinal': (frozenset(
4998 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4999 frozenset(['one', 'other'])),
5000 'select': (frozenset(), frozenset(['other'])),
5001 }
5002
5003 # Check if the message looks like an attempt to use ICU
5004 # plural. If yes - check if its syntax strictly matches ICU format.
5005 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5006 if not like:
5007 signatures.append((level, None, None, None))
5008 return
5009
5010 # Check for valid prefix and suffix
5011 m = re.match(
5012 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5013 r'(plural|selectordinal|select),\s*'
5014 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5015 if not m:
5016 return (('This message looks like an ICU plural, '
5017 'but does not follow ICU syntax.'), like.start(), like.end())
5018 starting, variable, kind, variant_pairs = m.groups()
5019 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5020 if depth:
5021 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5022 len(text))
5023 first = text[0]
5024 ending = text[last_pos:]
5025 if not starting:
5026 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5027 last_pos)
5028 if not ending or '}' not in ending:
5029 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5030 last_pos)
5031 elif first != '{':
5032 return (
5033 ('Invalid ICU format. Extra characters at the start of a complex '
5034 'message (go/icu-message-migration): "%s"') %
5035 starting, 0, len(starting))
5036 elif ending != '}':
5037 return (('Invalid ICU format. Extra characters at the end of a complex '
5038 'message (go/icu-message-migration): "%s"')
5039 % ending, last_pos - 1, len(text) - 1)
5040 if kind not in valid_types:
5041 return (('Unknown ICU message type %s. '
5042 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5043 known, required = valid_types[kind]
5044 defined_variants = set()
5045 for variant, variant_range, value, value_range in variants:
5046 start, end = variant_range
5047 if variant in defined_variants:
5048 return ('Variant "%s" is defined more than once' % variant,
5049 start, end)
5050 elif known and variant not in known:
5051 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5052 start, end)
5053 defined_variants.add(variant)
5054 # Check for nested structure
5055 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5056 if res:
5057 return (res[0], res[1] + value_range[0] + 1,
5058 res[2] + value_range[0] + 1)
5059 missing = required - defined_variants
5060 if missing:
5061 return ('Required variants missing: %s' % ', '.join(missing), 0,
5062 len(text))
5063 signatures.append((level, variable, kind, defined_variants))
5064
5065
5066 def _ParseIcuVariants(text, offset=0):
5067 """Parse variants part of ICU complex message.
5068
5069 Builds a tuple of variant names and values, as well as
5070 their offsets in the input string.
5071
5072 Args:
5073 text: a string to parse
5074 offset: additional offset to add to positions in the text to get correct
5075 position in the complete ICU string.
5076
5077 Returns:
5078 List of tuples, each tuple consist of four fields: variant name,
5079 variant name span (tuple of two integers), variant value, value
5080 span (tuple of two integers).
5081 """
5082 depth, start, end = 0, -1, -1
5083 variants = []
5084 key = None
5085 for idx, char in enumerate(text):
5086 if char == '{':
5087 if not depth:
5088 start = idx
5089 chunk = text[end + 1:start]
5090 key = chunk.strip()
5091 pos = offset + end + 1 + chunk.find(key)
5092 span = (pos, pos + len(key))
5093 depth += 1
5094 elif char == '}':
5095 if not depth:
5096 return variants, depth, offset + idx
5097 depth -= 1
5098 if not depth:
5099 end = idx
5100 variants.append((key, span, text[start:end + 1], (offset + start,
5101 offset + end + 1)))
5102 return variants, depth, offset + end + 1
5103
meacer8c0d3832019-12-26 21:46:165104 try:
5105 old_sys_path = sys.path
5106 sys.path = sys.path + [input_api.os_path.join(
5107 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5108 from helper import grd_helper
5109 finally:
5110 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145111
5112 for f in affected_grds:
5113 file_path = f.LocalPath()
5114 old_id_to_msg_map = {}
5115 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385116 # Note that this code doesn't check if the file has been deleted. This is
5117 # OK because it only uses the old and new file contents and doesn't load
5118 # the file via its path.
5119 # It's also possible that a file's content refers to a renamed or deleted
5120 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5121 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5122 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123 if file_path.endswith('.grdp'):
5124 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585125 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395126 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585128 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395129 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145130 else:
meacerff8a9b62019-12-10 19:43:585131 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585133 old_id_to_msg_map = grd_helper.GetGrdMessages(
5134 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145135 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585136 new_id_to_msg_map = grd_helper.GetGrdMessages(
5137 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138
5139 # Compute added, removed and modified message IDs.
5140 old_ids = set(old_id_to_msg_map)
5141 new_ids = set(new_id_to_msg_map)
5142 added_ids = new_ids - old_ids
5143 removed_ids = old_ids - new_ids
5144 modified_ids = set([])
5145 for key in old_ids.intersection(new_ids):
5146 if (old_id_to_msg_map[key].FormatXml()
5147 != new_id_to_msg_map[key].FormatXml()):
5148 modified_ids.add(key)
5149
5150 grd_name, ext = input_api.os_path.splitext(
5151 input_api.os_path.basename(file_path))
5152 screenshots_dir = input_api.os_path.join(
5153 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5154
Rainhard Findlingfc31844c52020-05-15 09:58:265155 if run_screenshot_check:
5156 # Check the screenshot directory for .png files. Warn if there is any.
5157 for png_path in affected_png_paths:
5158 if png_path.startswith(screenshots_dir):
5159 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145160
Rainhard Findlingfc31844c52020-05-15 09:58:265161 for added_id in added_ids:
5162 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145163
Rainhard Findlingfc31844c52020-05-15 09:58:265164 for modified_id in modified_ids:
5165 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145166
Rainhard Findlingfc31844c52020-05-15 09:58:265167 for removed_id in removed_ids:
5168 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5169
5170 # Check new and changed strings for ICU syntax errors.
5171 for key in added_ids.union(modified_ids):
5172 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5173 err = _ValidateIcuSyntax(msg, 0, [])
5174 if err is not None:
5175 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145176
5177 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265178 if run_screenshot_check:
5179 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005180 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265181 'Do not include actual screenshots in the changelist. Run '
5182 'tools/translate/upload_screenshots.py to upload them instead:',
5183 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145184
Rainhard Findlingfc31844c52020-05-15 09:58:265185 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005186 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265187 'You are adding or modifying UI strings.\n'
5188 'To ensure the best translations, take screenshots of the relevant UI '
5189 '(https://g.co/chrome/translation) and add these files to your '
5190 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145191
Rainhard Findlingfc31844c52020-05-15 09:58:265192 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005193 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265194 'You removed strings associated with these files. Remove:',
5195 sorted(unnecessary_sha1_files)))
5196 else:
5197 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5198 'screenshots check.'))
5199
5200 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075201 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265202 'ICU syntax errors were found in the following strings (problems or '
5203 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145204
5205 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125206
5207
5208def _CheckTranslationExpectations(input_api, output_api,
5209 repo_root=None,
5210 translation_expectations_path=None,
5211 grd_files=None):
5212 import sys
5213 affected_grds = [f for f in input_api.AffectedFiles()
5214 if (f.LocalPath().endswith('.grd') or
5215 f.LocalPath().endswith('.grdp'))]
5216 if not affected_grds:
5217 return []
5218
5219 try:
5220 old_sys_path = sys.path
5221 sys.path = sys.path + [
5222 input_api.os_path.join(
5223 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5224 from helper import git_helper
5225 from helper import translation_helper
5226 finally:
5227 sys.path = old_sys_path
5228
5229 # Check that translation expectations can be parsed and we can get a list of
5230 # translatable grd files. |repo_root| and |translation_expectations_path| are
5231 # only passed by tests.
5232 if not repo_root:
5233 repo_root = input_api.PresubmitLocalPath()
5234 if not translation_expectations_path:
5235 translation_expectations_path = input_api.os_path.join(
5236 repo_root, 'tools', 'gritsettings',
5237 'translation_expectations.pyl')
5238 if not grd_files:
5239 grd_files = git_helper.list_grds_in_repository(repo_root)
5240
5241 try:
5242 translation_helper.get_translatable_grds(repo_root, grd_files,
5243 translation_expectations_path)
5244 except Exception as e:
5245 return [output_api.PresubmitNotifyResult(
5246 'Failed to get a list of translatable grd files. This happens when:\n'
5247 ' - One of the modified grd or grdp files cannot be parsed or\n'
5248 ' - %s is not updated.\n'
5249 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5250 return []
Ken Rockotc31f4832020-05-29 18:58:515251
5252
5253def _CheckStableMojomChanges(input_api, output_api):
5254 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095255 changed_mojoms = input_api.AffectedFiles(
5256 include_deletes=True,
5257 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515258 delta = []
5259 for mojom in changed_mojoms:
5260 old_contents = ''.join(mojom.OldContents()) or None
5261 new_contents = ''.join(mojom.NewContents()) or None
5262 delta.append({
5263 'filename': mojom.LocalPath(),
5264 'old': '\n'.join(mojom.OldContents()) or None,
5265 'new': '\n'.join(mojom.NewContents()) or None,
5266 })
5267
5268 process = input_api.subprocess.Popen(
5269 [input_api.python_executable,
5270 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5271 'public', 'tools', 'mojom',
5272 'check_stable_mojom_compatibility.py'),
5273 '--src-root', input_api.PresubmitLocalPath()],
5274 stdin=input_api.subprocess.PIPE,
5275 stdout=input_api.subprocess.PIPE,
5276 stderr=input_api.subprocess.PIPE,
5277 universal_newlines=True)
5278 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5279 if process.returncode:
5280 return [output_api.PresubmitError(
5281 'One or more [Stable] mojom definitions appears to have been changed '
5282 'in a way that is not backward-compatible.',
5283 long_text=error)]
5284 return []