blob: 0122ef9ff6abcecc5092ad2051bb93125ccef66a [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/cronet/',
308 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51309 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36310 '^components/dom_distiller/',
Joey Scarr164d7072020-04-21 03:13:39311 '^components/download/internal/common/',
danakj7a2b7082019-05-21 21:13:51312 '^components/drive/',
313 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51314 '^components/feedback/',
315 '^components/flags_ui/',
316 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51317 '^components/guest_view/',
318 '^components/heap_profiling/',
319 '^components/history/',
320 '^components/image_fetcher/',
321 '^components/invalidation/',
322 '^components/keyed_service/',
323 '^components/login/',
324 '^components/metrics/',
325 '^components/metrics_services_manager/',
326 '^components/nacl/',
327 '^components/navigation_interception/',
328 '^components/net_log/',
329 '^components/network_time/',
330 '^components/ntp_snippets/',
331 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51332 '^components/offline_pages/',
333 '^components/omnibox/',
334 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51335 '^components/password_manager/',
336 '^components/payments/',
337 '^components/plugins/',
338 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51339 '^components/proxy_config/',
340 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51341 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51342 '^components/rlz/',
343 '^components/safe_browsing/',
344 '^components/search_engines/',
345 '^components/search_provider_logos/',
346 '^components/security_interstitials/',
347 '^components/security_state/',
348 '^components/services/',
349 '^components/sessions/',
350 '^components/signin/',
351 '^components/ssl_errors/',
352 '^components/storage_monitor/',
353 '^components/subresource_filter/',
354 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51355 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51356 '^components/sync_preferences/',
357 '^components/sync_sessions/',
358 '^components/test/',
359 '^components/tracing/',
360 '^components/translate/',
361 '^components/ukm/',
362 '^components/update_client/',
363 '^components/upload_list/',
364 '^components/variations/',
365 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51366 '^components/webcrypto/',
367 '^components/webdata/',
368 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51369 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20370 '^extensions/browser/',
371 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51372 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51373 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51374 '^ios/chrome/',
375 '^ios/components/',
376 '^ios/net/',
377 '^ios/web/',
378 '^ios/web_view/',
379 '^ipc/',
danakj7a2b7082019-05-21 21:13:51380 '^media/base/',
danakjc8576092019-11-26 19:01:36381 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51382 '^media/cast/',
383 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51384 '^media/filters/',
385 '^media/formats/',
386 '^media/gpu/',
387 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51388 '^media/renderers/',
Steve Kobes334b6ed2020-07-09 07:26:31389 '^net/http/',
390 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51391 '^ppapi/proxy/',
392 '^ppapi/shared_impl/',
393 '^ppapi/tests/',
394 '^ppapi/thunk/',
danakj7a2b7082019-05-21 21:13:51395 '^remoting/host/',
396 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51397 '^services/',
danakj7a2b7082019-05-21 21:13:51398 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51399 '^tools/clang/base_bind_rewriters/', # Intentional.
400 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51401))
[email protected]127f18ec2012-06-16 05:05:59402
Daniel Bratell609102be2019-03-27 20:53:21403# Format: Sequence of tuples containing:
404# * String pattern or, if starting with a slash, a regular expression.
405# * Sequence of strings to show when the pattern matches.
406# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
407# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59408_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20409 (
Dave Tapuska98199b612019-07-10 13:30:44410 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53411 (
412 'New code should not use NULL. Use nullptr instead.',
413 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20414 False,
thomasandersone7caaa9b2017-03-29 19:22:53415 (),
416 ),
Peter Kasting94a56c42019-10-25 21:54:04417 (
418 r'/\busing namespace ',
419 (
420 'Using directives ("using namespace x") are banned by the Google Style',
421 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
422 'Explicitly qualify symbols or use using declarations ("using x::foo").',
423 ),
424 True,
425 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
426 ),
Antonio Gomes07300d02019-03-13 20:59:57427 # Make sure that gtest's FRIEND_TEST() macro is not used; the
428 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
429 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53430 (
[email protected]23e6cbc2012-06-16 18:51:20431 'FRIEND_TEST(',
432 (
[email protected]e3c945502012-06-26 20:01:49433 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20434 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
435 ),
436 False,
[email protected]7345da02012-11-27 14:31:49437 (),
[email protected]23e6cbc2012-06-16 18:51:20438 ),
439 (
Dave Tapuska98199b612019-07-10 13:30:44440 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53441 (
442 'Chrome clients wishing to select events on X windows should use',
443 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
444 'you are selecting events from the GPU process, or if you are using',
445 'an XDisplay other than gfx::GetXDisplay().',
446 ),
447 True,
448 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40449 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04450 r"^ui[\\/]gl[\\/].*\.cc$",
451 r"^media[\\/]gpu[\\/].*\.cc$",
452 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37453 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
454 ),
thomasanderson4b569052016-09-14 20:15:53455 ),
456 (
Tom Anderson74d064b2020-07-08 03:47:32457 r'/\WX?(((Width|Height)(MM)?OfScreen)|(Display(Width|Height)))\(',
458 (
459 'Use the corresponding fields in x11::Screen instead.',
460 ),
461 True,
462 (),
463 ),
464 (
Dave Tapuska98199b612019-07-10 13:30:44465 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20466 (
thomasanderson11aa41dc2017-06-08 22:22:38467 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20468 ),
469 True,
470 (
Egor Paskoce145c42018-09-28 19:31:04471 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
472 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
473 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20474 ),
475 ),
476 (
tomhudsone2c14d552016-05-26 17:07:46477 'setMatrixClip',
478 (
479 'Overriding setMatrixClip() is prohibited; ',
480 'the base function is deprecated. ',
481 ),
482 True,
483 (),
484 ),
485 (
[email protected]52657f62013-05-20 05:30:31486 'SkRefPtr',
487 (
488 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22489 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31490 ),
491 True,
492 (),
493 ),
494 (
495 'SkAutoRef',
496 (
497 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
503 (
504 'SkAutoTUnref',
505 (
506 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22507 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31508 ),
509 True,
510 (),
511 ),
512 (
513 'SkAutoUnref',
514 (
515 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
516 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22517 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31518 ),
519 True,
520 (),
521 ),
[email protected]d89eec82013-12-03 14:10:59522 (
523 r'/HANDLE_EINTR\(.*close',
524 (
525 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
526 'descriptor will be closed, and it is incorrect to retry the close.',
527 'Either call close directly and ignore its return value, or wrap close',
528 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
529 ),
530 True,
531 (),
532 ),
533 (
534 r'/IGNORE_EINTR\((?!.*close)',
535 (
536 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
537 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
538 ),
539 True,
540 (
541 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04542 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
543 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59544 ),
545 ),
[email protected]ec5b3f02014-04-04 18:43:43546 (
547 r'/v8::Extension\(',
548 (
549 'Do not introduce new v8::Extensions into the code base, use',
550 'gin::Wrappable instead. See http://crbug.com/334679',
551 ),
552 True,
[email protected]f55c90ee62014-04-12 00:50:03553 (
Egor Paskoce145c42018-09-28 19:31:04554 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03555 ),
[email protected]ec5b3f02014-04-04 18:43:43556 ),
skyostilf9469f72015-04-20 10:38:52557 (
jame2d1a952016-04-02 00:27:10558 '#pragma comment(lib,',
559 (
560 'Specify libraries to link with in build files and not in the source.',
561 ),
562 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41563 (
tzik3f295992018-12-04 20:32:23564 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04565 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41566 ),
jame2d1a952016-04-02 00:27:10567 ),
fdorayc4ac18d2017-05-01 21:39:59568 (
Gabriel Charette7cc6c432018-04-25 20:52:02569 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59570 (
571 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
572 ),
573 False,
574 (),
575 ),
576 (
Gabriel Charette7cc6c432018-04-25 20:52:02577 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59578 (
579 'Consider using THREAD_CHECKER macros instead of the class directly.',
580 ),
581 False,
582 (),
583 ),
dbeamb6f4fde2017-06-15 04:03:06584 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06585 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
586 (
587 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
588 'deprecated (http://crbug.com/634507). Please avoid converting away',
589 'from the Time types in Chromium code, especially if any math is',
590 'being done on time values. For interfacing with platform/library',
591 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
592 'type converter methods instead. For faking TimeXXX values (for unit',
593 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
594 'other use cases, please contact base/time/OWNERS.',
595 ),
596 False,
597 (),
598 ),
599 (
dbeamb6f4fde2017-06-15 04:03:06600 'CallJavascriptFunctionUnsafe',
601 (
602 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
603 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
604 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
605 ),
606 False,
607 (
Egor Paskoce145c42018-09-28 19:31:04608 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
609 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
610 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06611 ),
612 ),
dskiba1474c2bfd62017-07-20 02:19:24613 (
614 'leveldb::DB::Open',
615 (
616 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
617 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
618 "Chrome's tracing, making their memory usage visible.",
619 ),
620 True,
621 (
622 r'^third_party/leveldatabase/.*\.(cc|h)$',
623 ),
Gabriel Charette0592c3a2017-07-26 12:02:04624 ),
625 (
Chris Mumfordc38afb62017-10-09 17:55:08626 'leveldb::NewMemEnv',
627 (
628 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58629 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
630 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08631 ),
632 True,
633 (
634 r'^third_party/leveldatabase/.*\.(cc|h)$',
635 ),
636 ),
637 (
Gabriel Charetted9839bc2017-07-29 14:17:47638 'RunLoop::QuitCurrent',
639 (
Robert Liao64b7ab22017-08-04 23:03:43640 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
641 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47642 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41643 False,
Gabriel Charetted9839bc2017-07-29 14:17:47644 (),
Gabriel Charettea44975052017-08-21 23:14:04645 ),
646 (
647 'base::ScopedMockTimeMessageLoopTaskRunner',
648 (
Gabriel Charette87cc1af2018-04-25 20:52:51649 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11650 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51651 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
652 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
653 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04654 ),
Gabriel Charette87cc1af2018-04-25 20:52:51655 False,
Gabriel Charettea44975052017-08-21 23:14:04656 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57657 ),
658 (
Dave Tapuska98199b612019-07-10 13:30:44659 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57660 (
661 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02662 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57663 ),
664 True,
665 (),
Francois Doray43670e32017-09-27 12:40:38666 ),
667 (
Peter Kasting991618a62019-06-17 22:00:09668 r'/\bstd::stoi\b',
669 (
670 'std::stoi uses exceptions to communicate results. ',
671 'Use base::StringToInt() instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
675 ),
676 (
677 r'/\bstd::stol\b',
678 (
679 'std::stol uses exceptions to communicate results. ',
680 'Use base::StringToInt() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stoul\b',
687 (
688 'std::stoul uses exceptions to communicate results. ',
689 'Use base::StringToUint() instead.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
695 r'/\bstd::stoll\b',
696 (
697 'std::stoll uses exceptions to communicate results. ',
698 'Use base::StringToInt64() instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
702 ),
703 (
704 r'/\bstd::stoull\b',
705 (
706 'std::stoull uses exceptions to communicate results. ',
707 'Use base::StringToUint64() instead.',
708 ),
709 True,
710 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
711 ),
712 (
713 r'/\bstd::stof\b',
714 (
715 'std::stof uses exceptions to communicate results. ',
716 'For locale-independent values, e.g. reading numbers from disk',
717 'profiles, use base::StringToDouble().',
718 'For user-visible values, parse using ICU.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
722 ),
723 (
724 r'/\bstd::stod\b',
725 (
726 'std::stod uses exceptions to communicate results. ',
727 'For locale-independent values, e.g. reading numbers from disk',
728 'profiles, use base::StringToDouble().',
729 'For user-visible values, parse using ICU.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::stold\b',
736 (
737 'std::stold uses exceptions to communicate results. ',
738 'For locale-independent values, e.g. reading numbers from disk',
739 'profiles, use base::StringToDouble().',
740 'For user-visible values, parse using ICU.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
Daniel Bratell69334cc2019-03-26 11:07:45746 r'/\bstd::to_string\b',
747 (
748 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09749 'For locale-independent strings, e.g. writing numbers to disk',
750 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45751 'For user-visible strings, use base::FormatNumber() and',
752 'the related functions in base/i18n/number_formatting.h.',
753 ),
Peter Kasting991618a62019-06-17 22:00:09754 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21755 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45756 ),
757 (
758 r'/\bstd::shared_ptr\b',
759 (
760 'std::shared_ptr should not be used. Use scoped_refptr instead.',
761 ),
762 True,
Andreas Haas63f58792019-11-07 10:56:44763 [_THIRD_PARTY_EXCEPT_BLINK,
764 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
765 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21766 ),
767 (
Peter Kasting991618a62019-06-17 22:00:09768 r'/\bstd::weak_ptr\b',
769 (
770 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
Daniel Bratell609102be2019-03-27 20:53:21776 r'/\blong long\b',
777 (
778 'long long is banned. Use stdint.h if you need a 64 bit number.',
779 ),
780 False, # Only a warning since it is already used.
781 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
782 ),
783 (
784 r'/\bstd::bind\b',
785 (
786 'std::bind is banned because of lifetime risks.',
787 'Use base::BindOnce or base::BindRepeating instead.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\b#include <chrono>\b',
794 (
795 '<chrono> overlaps with Time APIs in base. Keep using',
796 'base classes.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
800 ),
801 (
802 r'/\b#include <exception>\b',
803 (
804 'Exceptions are banned and disabled in Chromium.',
805 ),
806 True,
807 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
808 ),
809 (
810 r'/\bstd::function\b',
811 (
812 'std::function is banned. Instead use base::Callback which directly',
813 'supports Chromium\'s weak pointers, ref counting and more.',
814 ),
Peter Kasting991618a62019-06-17 22:00:09815 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21816 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
817 ),
818 (
819 r'/\b#include <random>\b',
820 (
821 'Do not use any random number engines from <random>. Instead',
822 'use base::RandomBitGenerator.',
823 ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
826 ),
827 (
828 r'/\bstd::ratio\b',
829 (
830 'std::ratio is banned by the Google Style Guide.',
831 ),
832 True,
833 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45834 ),
835 (
Francois Doray43670e32017-09-27 12:40:38836 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
837 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
838 (
839 'Use the new API in base/threading/thread_restrictions.h.',
840 ),
Gabriel Charette04b138f2018-08-06 00:03:22841 False,
Francois Doray43670e32017-09-27 12:40:38842 (),
843 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38844 (
danakj7a2b7082019-05-21 21:13:51845 r'/\bbase::Bind\(',
846 (
847 'Please use base::Bind{Once,Repeating} instead',
848 'of base::Bind. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Callback[<:]',
855 (
856 'Please use base::{Once,Repeating}Callback instead',
857 'of base::Callback. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
863 r'/\bbase::Closure\b',
864 (
865 'Please use base::{Once,Repeating}Closure instead',
866 'of base::Closure. (crbug.com/714018)',
867 ),
868 False,
Erik Staaba737d7602019-11-25 18:41:07869 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51870 ),
871 (
Michael Giuffrida7f93d6922019-04-19 14:39:58872 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 'RunMessageLoop is deprecated, use RunLoop instead.',
875 ),
876 False,
877 (),
878 ),
879 (
Dave Tapuska98199b612019-07-10 13:30:44880 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19881 (
882 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
891 "if you're convinced you need this.",
892 ),
893 False,
894 (),
895 ),
896 (
Dave Tapuska98199b612019-07-10 13:30:44897 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19898 (
899 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04900 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19901 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
902 'async events instead of flushing threads.',
903 ),
904 False,
905 (),
906 ),
907 (
908 r'MessageLoopRunner',
909 (
910 'MessageLoopRunner is deprecated, use RunLoop instead.',
911 ),
912 False,
913 (),
914 ),
915 (
Dave Tapuska98199b612019-07-10 13:30:44916 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19917 (
918 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
919 "gab@ if you found a use case where this is the only solution.",
920 ),
921 False,
922 (),
923 ),
924 (
Victor Costane48a2e82019-03-15 22:02:34925 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16926 (
Victor Costane48a2e82019-03-15 22:02:34927 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16928 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
929 ),
930 True,
931 (
932 r'^sql/initialization\.(cc|h)$',
933 r'^third_party/sqlite/.*\.(c|cc|h)$',
934 ),
935 ),
Matt Menke7f520a82018-03-28 21:38:37936 (
Dave Tapuska98199b612019-07-10 13:30:44937 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47938 (
939 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
940 'base::RandomShuffle instead.'
941 ),
942 True,
943 (),
944 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24945 (
946 'ios/web/public/test/http_server',
947 (
948 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
949 ),
950 False,
951 (),
952 ),
Robert Liao764c9492019-01-24 18:46:28953 (
954 'GetAddressOf',
955 (
956 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
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',
Andrew Grieveb838d832019-02-11 16:55:221347 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001348 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591350 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421352 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/filter_zip.pydeps',
1355 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361356 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581358 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261360 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011361 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/gyp/lint.pydeps',
1363 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361364 'build/android/gyp/merge_manifest.pydeps',
1365 'build/android/gyp/prepare_resources.pydeps',
1366 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461367 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241368 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361369 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461370 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561371 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361372 'build/android/incremental_install/generate_android_manifest.pydeps',
1373 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361374 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271375 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1376 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001377 'components/cronet/tools/generate_javadoc.pydeps',
1378 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381379 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001380 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381381 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421382 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1383 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131384 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191385 ('third_party/blink/renderer/bindings/scripts/'
1386 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061387 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221388 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401389]
1390
wnwenbdc444e2016-05-25 13:44:151391
agrievef32bcc72016-04-04 14:57:401392_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1393
1394
Eric Boren6fd2b932018-01-25 15:05:081395# Bypass the AUTHORS check for these accounts.
1396_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591397 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451398 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591399 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521400 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1401 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041402 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271403 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041404 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301405 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081406
1407
Daniel Bratell65b033262019-04-23 08:17:061408def _IsCPlusPlusFile(input_api, file_path):
1409 """Returns True if this file contains C++-like code (and not Python,
1410 Go, Java, MarkDown, ...)"""
1411
1412 ext = input_api.os_path.splitext(file_path)[1]
1413 # This list is compatible with CppChecker.IsCppFile but we should
1414 # consider adding ".c" to it. If we do that we can use this function
1415 # at more places in the code.
1416 return ext in (
1417 '.h',
1418 '.cc',
1419 '.cpp',
1420 '.m',
1421 '.mm',
1422 )
1423
1424def _IsCPlusPlusHeaderFile(input_api, file_path):
1425 return input_api.os_path.splitext(file_path)[1] == ".h"
1426
1427
1428def _IsJavaFile(input_api, file_path):
1429 return input_api.os_path.splitext(file_path)[1] == ".java"
1430
1431
1432def _IsProtoFile(input_api, file_path):
1433 return input_api.os_path.splitext(file_path)[1] == ".proto"
1434
[email protected]55459852011-08-10 15:17:191435def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1436 """Attempts to prevent use of functions intended only for testing in
1437 non-testing code. For now this is just a best-effort implementation
1438 that ignores header files and may have some false positives. A
1439 better implementation would probably need a proper C++ parser.
1440 """
1441 # We only scan .cc files and the like, as the declaration of
1442 # for-testing functions in header files are hard to distinguish from
1443 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491444 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191445
jochenc0d4808c2015-07-27 09:25:421446 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191447 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091448 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191449 exclusion_pattern = input_api.re.compile(
1450 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1451 base_function_pattern, base_function_pattern))
1452
1453 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441454 black_list = (_EXCLUDED_PATHS +
1455 _TEST_CODE_EXCLUDED_PATHS +
1456 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191457 return input_api.FilterSourceFile(
1458 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491459 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191460 black_list=black_list)
1461
1462 problems = []
1463 for f in input_api.AffectedSourceFiles(FilterFile):
1464 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241465 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031466 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461467 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031468 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191469 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031470 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191471
1472 if problems:
[email protected]f7051d52013-04-02 18:31:421473 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031474 else:
1475 return []
[email protected]55459852011-08-10 15:17:191476
1477
Vaclav Brozek7dbc28c2018-03-27 08:35:231478def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1479 """This is a simplified version of
1480 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1481 """
1482 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1483 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1484 name_pattern = r'ForTest(s|ing)?'
1485 # Describes an occurrence of "ForTest*" inside a // comment.
1486 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1487 # Catch calls.
1488 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1489 # Ignore definitions. (Comments are ignored separately.)
1490 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1491
1492 problems = []
1493 sources = lambda x: input_api.FilterSourceFile(
1494 x,
1495 black_list=(('(?i).*test', r'.*\/junit\/')
1496 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491497 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231498 )
1499 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1500 local_path = f.LocalPath()
1501 is_inside_javadoc = False
1502 for line_number, line in f.ChangedContents():
1503 if is_inside_javadoc and javadoc_end_re.search(line):
1504 is_inside_javadoc = False
1505 if not is_inside_javadoc and javadoc_start_re.search(line):
1506 is_inside_javadoc = True
1507 if is_inside_javadoc:
1508 continue
1509 if (inclusion_re.search(line) and
1510 not comment_re.search(line) and
1511 not exclusion_re.search(line)):
1512 problems.append(
1513 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1514
1515 if problems:
1516 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1517 else:
1518 return []
1519
1520
[email protected]10689ca2011-09-02 02:31:541521def _CheckNoIOStreamInHeaders(input_api, output_api):
1522 """Checks to make sure no .h files include <iostream>."""
1523 files = []
1524 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1525 input_api.re.MULTILINE)
1526 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1527 if not f.LocalPath().endswith('.h'):
1528 continue
1529 contents = input_api.ReadFile(f)
1530 if pattern.search(contents):
1531 files.append(f)
1532
1533 if len(files):
yolandyandaabc6d2016-04-18 18:29:391534 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061535 'Do not #include <iostream> in header files, since it inserts static '
1536 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541537 '#include <ostream>. See http://crbug.com/94794',
1538 files) ]
1539 return []
1540
Danil Chapovalov3518f362018-08-11 16:13:431541def _CheckNoStrCatRedefines(input_api, output_api):
1542 """Checks no windows headers with StrCat redefined are included directly."""
1543 files = []
1544 pattern_deny = input_api.re.compile(
1545 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1546 input_api.re.MULTILINE)
1547 pattern_allow = input_api.re.compile(
1548 r'^#include\s"base/win/windows_defines.inc"',
1549 input_api.re.MULTILINE)
1550 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1551 contents = input_api.ReadFile(f)
1552 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1553 files.append(f.LocalPath())
1554
1555 if len(files):
1556 return [output_api.PresubmitError(
1557 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1558 'directly since they pollute code with StrCat macro. Instead, '
1559 'include matching header from base/win. See http://crbug.com/856536',
1560 files) ]
1561 return []
1562
[email protected]10689ca2011-09-02 02:31:541563
[email protected]72df4e782012-06-21 16:28:181564def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521565 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181566 problems = []
1567 for f in input_api.AffectedFiles():
1568 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1569 continue
1570
1571 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041572 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181573 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1574
1575 if not problems:
1576 return []
1577 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1578 '\n'.join(problems))]
1579
Dominic Battre033531052018-09-24 15:45:341580def _CheckNoDISABLETypoInTests(input_api, output_api):
1581 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1582
1583 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1584 instead of DISABLED_. To filter false positives, reports are only generated
1585 if a corresponding MAYBE_ line exists.
1586 """
1587 problems = []
1588
1589 # The following two patterns are looked for in tandem - is a test labeled
1590 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1591 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1592 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1593
1594 # This is for the case that a test is disabled on all platforms.
1595 full_disable_pattern = input_api.re.compile(
1596 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1597 input_api.re.MULTILINE)
1598
Katie Df13948e2018-09-25 07:33:441599 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341600 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1601 continue
1602
1603 # Search for MABYE_, DISABLE_ pairs.
1604 disable_lines = {} # Maps of test name to line number.
1605 maybe_lines = {}
1606 for line_num, line in f.ChangedContents():
1607 disable_match = disable_pattern.search(line)
1608 if disable_match:
1609 disable_lines[disable_match.group(1)] = line_num
1610 maybe_match = maybe_pattern.search(line)
1611 if maybe_match:
1612 maybe_lines[maybe_match.group(1)] = line_num
1613
1614 # Search for DISABLE_ occurrences within a TEST() macro.
1615 disable_tests = set(disable_lines.keys())
1616 maybe_tests = set(maybe_lines.keys())
1617 for test in disable_tests.intersection(maybe_tests):
1618 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1619
1620 contents = input_api.ReadFile(f)
1621 full_disable_match = full_disable_pattern.search(contents)
1622 if full_disable_match:
1623 problems.append(' %s' % f.LocalPath())
1624
1625 if not problems:
1626 return []
1627 return [
1628 output_api.PresubmitPromptWarning(
1629 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1630 '\n'.join(problems))
1631 ]
1632
[email protected]72df4e782012-06-21 16:28:181633
danakj61c1aa22015-10-26 19:55:521634def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571635 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521636 errors = []
Hans Wennborg944479f2020-06-25 21:39:251637 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521638 input_api.re.MULTILINE)
1639 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1640 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1641 continue
1642 for lnum, line in f.ChangedContents():
1643 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171644 errors.append(output_api.PresubmitError(
1645 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571646 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171647 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521648 return errors
1649
1650
Makoto Shimazu3ad422cd2019-05-08 02:35:141651def _FindHistogramNameInChunk(histogram_name, chunk):
1652 """Tries to find a histogram name or prefix in a line.
1653
1654 Returns the existence of the histogram name, or None if it needs more chunk
1655 to determine."""
mcasasb7440c282015-02-04 14:52:191656 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1657 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141658 if '<affected-histogram' in chunk:
1659 # If the tag is not completed, needs more chunk to get the name.
1660 if not '>' in chunk:
1661 return None
1662 if not 'name="' in chunk:
1663 return False
1664 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1665 # expect the only attribute is the name.
1666 histogram_prefix = chunk.split('"')[1]
1667 return histogram_prefix in histogram_name
1668 # Typically the whole histogram name should in the line.
1669 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191670
1671
1672def _CheckUmaHistogramChanges(input_api, output_api):
1673 """Check that UMA histogram names in touched lines can still be found in other
1674 lines of the patch or in histograms.xml. Note that this check would not catch
1675 the reverse: changes in histograms.xml not matched in the code itself."""
1676 touched_histograms = []
1677 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471678 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1679 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1680 name_pattern = r'"(.*?)"'
1681 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1682 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1683 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1684 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1685 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171686 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191687 for f in input_api.AffectedFiles():
1688 # If histograms.xml itself is modified, keep the modified lines for later.
1689 if f.LocalPath().endswith(('histograms.xml')):
1690 histograms_xml_modifications = f.ChangedContents()
1691 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471692 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1693 single_line_re = single_line_c_re
1694 split_line_prefix_re = split_line_c_prefix_re
1695 elif f.LocalPath().endswith(('java')):
1696 single_line_re = single_line_java_re
1697 split_line_prefix_re = split_line_java_prefix_re
1698 else:
mcasasb7440c282015-02-04 14:52:191699 continue
1700 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171701 if last_line_matched_prefix:
1702 suffix_found = split_line_suffix_re.search(line)
1703 if suffix_found :
1704 touched_histograms.append([suffix_found.group(1), f, line_num])
1705 last_line_matched_prefix = False
1706 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061707 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191708 if found:
1709 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171710 continue
1711 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191712
1713 # Search for the touched histogram names in the local modifications to
1714 # histograms.xml, and, if not found, on the base histograms.xml file.
1715 unmatched_histograms = []
1716 for histogram_info in touched_histograms:
1717 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141718 chunk = ''
mcasasb7440c282015-02-04 14:52:191719 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141720 chunk += line
1721 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1722 if histogram_name_found is None:
1723 continue
1724 chunk = ''
mcasasb7440c282015-02-04 14:52:191725 if histogram_name_found:
1726 break
1727 if not histogram_name_found:
1728 unmatched_histograms.append(histogram_info)
1729
eromanb90c82e7e32015-04-01 15:13:491730 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191731 problems = []
1732 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491733 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191734 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451735 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191736 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141737 chunk = ''
mcasasb7440c282015-02-04 14:52:191738 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141739 chunk += line
1740 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1741 chunk)
1742 if histogram_name_found is None:
1743 continue
1744 chunk = ''
mcasasb7440c282015-02-04 14:52:191745 if histogram_name_found:
1746 break
1747 if not histogram_name_found:
1748 problems.append(' [%s:%d] %s' %
1749 (f.LocalPath(), line_num, histogram_name))
1750
1751 if not problems:
1752 return []
1753 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1754 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491755 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191756
wnwenbdc444e2016-05-25 13:44:151757
yolandyandaabc6d2016-04-18 18:29:391758def _CheckFlakyTestUsage(input_api, output_api):
1759 """Check that FlakyTest annotation is our own instead of the android one"""
1760 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1761 files = []
1762 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1763 if f.LocalPath().endswith('Test.java'):
1764 if pattern.search(input_api.ReadFile(f)):
1765 files.append(f)
1766 if len(files):
1767 return [output_api.PresubmitError(
1768 'Use org.chromium.base.test.util.FlakyTest instead of '
1769 'android.test.FlakyTest',
1770 files)]
1771 return []
mcasasb7440c282015-02-04 14:52:191772
wnwenbdc444e2016-05-25 13:44:151773
[email protected]8ea5d4b2011-09-13 21:49:221774def _CheckNoNewWStrings(input_api, output_api):
1775 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271776 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221777 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201778 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571779 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341780 '/win/' in f.LocalPath() or
1781 'chrome_elf' in f.LocalPath() or
1782 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201783 continue
[email protected]8ea5d4b2011-09-13 21:49:221784
[email protected]a11dbe9b2012-08-07 01:32:581785 allowWString = False
[email protected]b5c24292011-11-28 14:38:201786 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581787 if 'presubmit: allow wstring' in line:
1788 allowWString = True
1789 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271790 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581791 allowWString = False
1792 else:
1793 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221794
[email protected]55463aa62011-10-12 00:48:271795 if not problems:
1796 return []
1797 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581798 ' If you are calling a cross-platform API that accepts a wstring, '
1799 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271800 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221801
1802
[email protected]2a8ac9c2011-10-19 17:20:441803def _CheckNoDEPSGIT(input_api, output_api):
1804 """Make sure .DEPS.git is never modified manually."""
1805 if any(f.LocalPath().endswith('.DEPS.git') for f in
1806 input_api.AffectedFiles()):
1807 return [output_api.PresubmitError(
1808 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1809 'automated system based on what\'s in DEPS and your changes will be\n'
1810 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501811 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1812 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441813 'for more information')]
1814 return []
1815
1816
tandriief664692014-09-23 14:51:471817def _CheckValidHostsInDEPS(input_api, output_api):
1818 """Checks that DEPS file deps are from allowed_hosts."""
1819 # Run only if DEPS file has been modified to annoy fewer bystanders.
1820 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1821 return []
1822 # Outsource work to gclient verify
1823 try:
John Budorickf20c0042019-04-25 23:23:401824 gclient_path = input_api.os_path.join(
1825 input_api.PresubmitLocalPath(),
1826 'third_party', 'depot_tools', 'gclient.py')
1827 input_api.subprocess.check_output(
1828 [input_api.python_executable, gclient_path, 'verify'],
1829 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471830 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201831 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471832 return [output_api.PresubmitError(
1833 'DEPS file must have only git dependencies.',
1834 long_text=error.output)]
1835
1836
Mario Sanchez Prada2472cab2019-09-18 10:58:311837def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1838 type_name, message):
1839 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1840
1841 Returns an string composed of the name of the file, the line number where the
1842 match has been found and the additional text passed as |message| in case the
1843 target type name matches the text inside the line passed as parameter.
1844 """
Peng Huang9c5949a02020-06-11 19:20:541845 result = []
1846
1847 if line.endswith(" nocheck"):
1848 return result
1849
Mario Sanchez Prada2472cab2019-09-18 10:58:311850 matched = False
1851 if type_name[0:1] == '/':
1852 regex = type_name[1:]
1853 if input_api.re.search(regex, line):
1854 matched = True
1855 elif type_name in line:
1856 matched = True
1857
Mario Sanchez Prada2472cab2019-09-18 10:58:311858 if matched:
1859 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1860 for message_line in message:
1861 result.append(' %s' % message_line)
1862
1863 return result
1864
1865
[email protected]127f18ec2012-06-16 05:05:591866def _CheckNoBannedFunctions(input_api, output_api):
1867 """Make sure that banned functions are not used."""
1868 warnings = []
1869 errors = []
1870
wnwenbdc444e2016-05-25 13:44:151871 def IsBlacklisted(affected_file, blacklist):
1872 local_path = affected_file.LocalPath()
1873 for item in blacklist:
1874 if input_api.re.match(item, local_path):
1875 return True
1876 return False
1877
Peter K. Lee6c03ccff2019-07-15 14:40:051878 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541879 local_path = affected_file.LocalPath()
1880 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1881 return False
1882 basename = input_api.os_path.basename(local_path)
1883 if 'ios' in basename.split('_'):
1884 return True
1885 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1886 if sep and 'ios' in local_path.split(sep):
1887 return True
1888 return False
1889
wnwenbdc444e2016-05-25 13:44:151890 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311891 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1892 func_name, message)
1893 if problems:
wnwenbdc444e2016-05-25 13:44:151894 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311895 errors.extend(problems)
1896 else:
1897 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151898
Eric Stevensona9a980972017-09-23 00:04:411899 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1900 for f in input_api.AffectedFiles(file_filter=file_filter):
1901 for line_num, line in f.ChangedContents():
1902 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1903 CheckForMatch(f, line_num, line, func_name, message, error)
1904
[email protected]127f18ec2012-06-16 05:05:591905 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1906 for f in input_api.AffectedFiles(file_filter=file_filter):
1907 for line_num, line in f.ChangedContents():
1908 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151909 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591910
Peter K. Lee6c03ccff2019-07-15 14:40:051911 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541912 for line_num, line in f.ChangedContents():
1913 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1914 CheckForMatch(f, line_num, line, func_name, message, error)
1915
Peter K. Lee6c03ccff2019-07-15 14:40:051916 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1917 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1918 for line_num, line in f.ChangedContents():
1919 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1920 CheckForMatch(f, line_num, line, func_name, message, error)
1921
[email protected]127f18ec2012-06-16 05:05:591922 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1923 for f in input_api.AffectedFiles(file_filter=file_filter):
1924 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491925 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491926 if IsBlacklisted(f, excluded_paths):
1927 continue
wnwenbdc444e2016-05-25 13:44:151928 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591929
1930 result = []
1931 if (warnings):
1932 result.append(output_api.PresubmitPromptWarning(
1933 'Banned functions were used.\n' + '\n'.join(warnings)))
1934 if (errors):
1935 result.append(output_api.PresubmitError(
1936 'Banned functions were used.\n' + '\n'.join(errors)))
1937 return result
1938
1939
Michael Thiessen44457642020-02-06 00:24:151940def _CheckAndroidNoBannedImports(input_api, output_api):
1941 """Make sure that banned java imports are not used."""
1942 errors = []
1943
1944 def IsException(path, exceptions):
1945 for exception in exceptions:
1946 if (path.startswith(exception)):
1947 return True
1948 return False
1949
1950 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1951 for f in input_api.AffectedFiles(file_filter=file_filter):
1952 for line_num, line in f.ChangedContents():
1953 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1954 if IsException(f.LocalPath(), exceptions):
1955 continue;
1956 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1957 'import ' + import_name, message)
1958 if problems:
1959 errors.extend(problems)
1960 result = []
1961 if (errors):
1962 result.append(output_api.PresubmitError(
1963 'Banned imports were used.\n' + '\n'.join(errors)))
1964 return result
1965
1966
Mario Sanchez Prada2472cab2019-09-18 10:58:311967def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1968 """Make sure that old Mojo types are not used."""
1969 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571970 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311971
Mario Sanchez Pradaaab91382019-12-19 08:57:091972 # For any path that is not an "ok" or an "error" path, a warning will be
1973 # raised if deprecated mojo types are found.
1974 ok_paths = ['components/arc']
1975 error_paths = ['third_party/blink', 'content']
1976
Mario Sanchez Prada2472cab2019-09-18 10:58:311977 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1978 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571979 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091980 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311981 continue
1982
1983 for line_num, line in f.ChangedContents():
1984 for func_name, message in _DEPRECATED_MOJO_TYPES:
1985 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1986 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571987
Mario Sanchez Prada2472cab2019-09-18 10:58:311988 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091989 # Raise errors inside |error_paths| and warnings everywhere else.
1990 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571991 errors.extend(problems)
1992 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311993 warnings.extend(problems)
1994
1995 result = []
1996 if (warnings):
1997 result.append(output_api.PresubmitPromptWarning(
1998 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571999 if (errors):
2000 result.append(output_api.PresubmitError(
2001 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312002 return result
2003
2004
[email protected]6c063c62012-07-11 19:11:062005def _CheckNoPragmaOnce(input_api, output_api):
2006 """Make sure that banned functions are not used."""
2007 files = []
2008 pattern = input_api.re.compile(r'^#pragma\s+once',
2009 input_api.re.MULTILINE)
2010 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2011 if not f.LocalPath().endswith('.h'):
2012 continue
2013 contents = input_api.ReadFile(f)
2014 if pattern.search(contents):
2015 files.append(f)
2016
2017 if files:
2018 return [output_api.PresubmitError(
2019 'Do not use #pragma once in header files.\n'
2020 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2021 files)]
2022 return []
2023
[email protected]127f18ec2012-06-16 05:05:592024
[email protected]e7479052012-09-19 00:26:122025def _CheckNoTrinaryTrueFalse(input_api, output_api):
2026 """Checks to make sure we don't introduce use of foo ? true : false."""
2027 problems = []
2028 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2029 for f in input_api.AffectedFiles():
2030 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2031 continue
2032
2033 for line_num, line in f.ChangedContents():
2034 if pattern.match(line):
2035 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2036
2037 if not problems:
2038 return []
2039 return [output_api.PresubmitPromptWarning(
2040 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2041 '\n'.join(problems))]
2042
2043
[email protected]55f9f382012-07-31 11:02:182044def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282045 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182046 change. Breaking - rules is an error, breaking ! rules is a
2047 warning.
2048 """
mohan.reddyf21db962014-10-16 12:26:472049 import sys
[email protected]55f9f382012-07-31 11:02:182050 # We need to wait until we have an input_api object and use this
2051 # roundabout construct to import checkdeps because this file is
2052 # eval-ed and thus doesn't have __file__.
2053 original_sys_path = sys.path
2054 try:
2055 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472056 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182057 import checkdeps
[email protected]55f9f382012-07-31 11:02:182058 from rules import Rule
2059 finally:
2060 # Restore sys.path to what it was before.
2061 sys.path = original_sys_path
2062
2063 added_includes = []
rhalavati08acd232017-04-03 07:23:282064 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242065 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182066 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062067 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502068 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082069 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062070 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502071 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082072 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062073 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502074 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082075 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182076
[email protected]26385172013-05-09 23:11:352077 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182078
2079 error_descriptions = []
2080 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282081 error_subjects = set()
2082 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182083 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2084 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082085 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182086 description_with_path = '%s\n %s' % (path, rule_description)
2087 if rule_type == Rule.DISALLOW:
2088 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282089 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182090 else:
2091 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282092 warning_subjects.add("#includes")
2093
2094 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2095 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082096 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282097 description_with_path = '%s\n %s' % (path, rule_description)
2098 if rule_type == Rule.DISALLOW:
2099 error_descriptions.append(description_with_path)
2100 error_subjects.add("imports")
2101 else:
2102 warning_descriptions.append(description_with_path)
2103 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182104
Jinsuk Kim5a092672017-10-24 22:42:242105 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022106 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082107 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242108 description_with_path = '%s\n %s' % (path, rule_description)
2109 if rule_type == Rule.DISALLOW:
2110 error_descriptions.append(description_with_path)
2111 error_subjects.add("imports")
2112 else:
2113 warning_descriptions.append(description_with_path)
2114 warning_subjects.add("imports")
2115
[email protected]55f9f382012-07-31 11:02:182116 results = []
2117 if error_descriptions:
2118 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282119 'You added one or more %s that violate checkdeps rules.'
2120 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182121 error_descriptions))
2122 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422123 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282124 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182125 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282126 '%s? See relevant DEPS file(s) for details and contacts.' %
2127 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182128 warning_descriptions))
2129 return results
2130
2131
[email protected]fbcafe5a2012-08-08 15:31:222132def _CheckFilePermissions(input_api, output_api):
2133 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152134 if input_api.platform == 'win32':
2135 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292136 checkperms_tool = input_api.os_path.join(
2137 input_api.PresubmitLocalPath(),
2138 'tools', 'checkperms', 'checkperms.py')
2139 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472140 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392141 with input_api.CreateTemporaryFile() as file_list:
2142 for f in input_api.AffectedFiles():
2143 # checkperms.py file/directory arguments must be relative to the
2144 # repository.
2145 file_list.write(f.LocalPath() + '\n')
2146 file_list.close()
2147 args += ['--file-list', file_list.name]
2148 try:
2149 input_api.subprocess.check_output(args)
2150 return []
2151 except input_api.subprocess.CalledProcessError as error:
2152 return [output_api.PresubmitError(
2153 'checkperms.py failed:',
2154 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222155
2156
robertocn832f5992017-01-04 19:01:302157def _CheckTeamTags(input_api, output_api):
2158 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2159 checkteamtags_tool = input_api.os_path.join(
2160 input_api.PresubmitLocalPath(),
2161 'tools', 'checkteamtags', 'checkteamtags.py')
2162 args = [input_api.python_executable, checkteamtags_tool,
2163 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222164 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302165 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2166 'OWNERS']
2167 try:
2168 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052169 warnings = input_api.subprocess.check_output(args + files).splitlines()
2170 if warnings:
2171 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302172 return []
2173 except input_api.subprocess.CalledProcessError as error:
2174 return [output_api.PresubmitError(
2175 'checkteamtags.py failed:',
2176 long_text=error.output)]
2177
2178
[email protected]c8278b32012-10-30 20:35:492179def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2180 """Makes sure we don't include ui/aura/window_property.h
2181 in header files.
2182 """
2183 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2184 errors = []
2185 for f in input_api.AffectedFiles():
2186 if not f.LocalPath().endswith('.h'):
2187 continue
2188 for line_num, line in f.ChangedContents():
2189 if pattern.match(line):
2190 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2191
2192 results = []
2193 if errors:
2194 results.append(output_api.PresubmitError(
2195 'Header files should not include ui/aura/window_property.h', errors))
2196 return results
2197
2198
[email protected]70ca77752012-11-20 03:45:032199def _CheckForVersionControlConflictsInFile(input_api, f):
2200 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2201 errors = []
2202 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162203 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232204 # First-level headers in markdown look a lot like version control
2205 # conflict markers. http://daringfireball.net/projects/markdown/basics
2206 continue
[email protected]70ca77752012-11-20 03:45:032207 if pattern.match(line):
2208 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2209 return errors
2210
2211
2212def _CheckForVersionControlConflicts(input_api, output_api):
2213 """Usually this is not intentional and will cause a compile failure."""
2214 errors = []
2215 for f in input_api.AffectedFiles():
2216 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2217
2218 results = []
2219 if errors:
2220 results.append(output_api.PresubmitError(
2221 'Version control conflict markers found, please resolve.', errors))
2222 return results
2223
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202224
estadee17314a02017-01-12 16:22:162225def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2226 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2227 errors = []
2228 for f in input_api.AffectedFiles():
2229 for line_num, line in f.ChangedContents():
2230 if pattern.search(line):
2231 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2232
2233 results = []
2234 if errors:
2235 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502236 'Found Google support URL addressed by answer number. Please replace '
2237 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162238 return results
2239
[email protected]70ca77752012-11-20 03:45:032240
[email protected]06e6d0ff2012-12-11 01:36:442241def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2242 def FilterFile(affected_file):
2243 """Filter function for use with input_api.AffectedSourceFiles,
2244 below. This filters out everything except non-test files from
2245 top-level directories that generally speaking should not hard-code
2246 service URLs (e.g. src/android_webview/, src/content/ and others).
2247 """
2248 return input_api.FilterSourceFile(
2249 affected_file,
Egor Paskoce145c42018-09-28 19:31:042250 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442251 black_list=(_EXCLUDED_PATHS +
2252 _TEST_CODE_EXCLUDED_PATHS +
2253 input_api.DEFAULT_BLACK_LIST))
2254
reillyi38965732015-11-16 18:27:332255 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2256 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462257 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2258 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442259 problems = [] # items are (filename, line_number, line)
2260 for f in input_api.AffectedSourceFiles(FilterFile):
2261 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462262 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442263 problems.append((f.LocalPath(), line_num, line))
2264
2265 if problems:
[email protected]f7051d52013-04-02 18:31:422266 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442267 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582268 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442269 [' %s:%d: %s' % (
2270 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032271 else:
2272 return []
[email protected]06e6d0ff2012-12-11 01:36:442273
2274
James Cook6b6597c2019-11-06 22:05:292275def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2276 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2277 def FileFilter(affected_file):
2278 """Includes directories known to be Chrome OS only."""
2279 return input_api.FilterSourceFile(
2280 affected_file,
2281 white_list=('^ash/',
2282 '^chromeos/', # Top-level src/chromeos.
2283 '/chromeos/', # Any path component.
2284 '^components/arc',
2285 '^components/exo'),
2286 black_list=(input_api.DEFAULT_BLACK_LIST))
2287
2288 prefs = []
2289 priority_prefs = []
2290 for f in input_api.AffectedFiles(file_filter=FileFilter):
2291 for line_num, line in f.ChangedContents():
2292 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2293 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2294 prefs.append(' %s' % line)
2295 if input_api.re.search(
2296 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2297 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2298 priority_prefs.append(' %s' % line)
2299
2300 results = []
2301 if (prefs):
2302 results.append(output_api.PresubmitPromptWarning(
2303 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2304 'by browser sync settings. If these prefs should be controlled by OS '
2305 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2306 if (priority_prefs):
2307 results.append(output_api.PresubmitPromptWarning(
2308 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2309 'controlled by browser sync settings. If these prefs should be '
2310 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2311 'instead.\n' + '\n'.join(prefs)))
2312 return results
2313
2314
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492315# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272316def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2317 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312318 The native_client_sdk directory is excluded because it has auto-generated PNG
2319 files for documentation.
[email protected]d2530012013-01-25 16:39:272320 """
[email protected]d2530012013-01-25 16:39:272321 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492322 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042323 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312324 file_filter = lambda f: input_api.FilterSourceFile(
2325 f, white_list=white_list, black_list=black_list)
2326 for f in input_api.AffectedFiles(include_deletes=False,
2327 file_filter=file_filter):
2328 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272329
2330 results = []
2331 if errors:
2332 results.append(output_api.PresubmitError(
2333 'The name of PNG files should not have abbreviations. \n'
2334 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2335 'Contact [email protected] if you have questions.', errors))
2336 return results
2337
2338
Daniel Cheng4dcdb6b2017-04-13 08:30:172339def _ExtractAddRulesFromParsedDeps(parsed_deps):
2340 """Extract the rules that add dependencies from a parsed DEPS file.
2341
2342 Args:
2343 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2344 add_rules = set()
2345 add_rules.update([
2346 rule[1:] for rule in parsed_deps.get('include_rules', [])
2347 if rule.startswith('+') or rule.startswith('!')
2348 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502349 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172350 {}).iteritems():
2351 add_rules.update([
2352 rule[1:] for rule in rules
2353 if rule.startswith('+') or rule.startswith('!')
2354 ])
2355 return add_rules
2356
2357
2358def _ParseDeps(contents):
2359 """Simple helper for parsing DEPS files."""
2360 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172361 class _VarImpl:
2362
2363 def __init__(self, local_scope):
2364 self._local_scope = local_scope
2365
2366 def Lookup(self, var_name):
2367 """Implements the Var syntax."""
2368 try:
2369 return self._local_scope['vars'][var_name]
2370 except KeyError:
2371 raise Exception('Var is not defined: %s' % var_name)
2372
2373 local_scope = {}
2374 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172375 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592376 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172377 }
2378 exec contents in global_scope, local_scope
2379 return local_scope
2380
2381
2382def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082383 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412384 a set of DEPS entries that we should look up.
2385
2386 For a directory (rather than a specific filename) we fake a path to
2387 a specific filename by adding /DEPS. This is chosen as a file that
2388 will seldom or never be subject to per-file include_rules.
2389 """
[email protected]2b438d62013-11-14 17:54:142390 # We ignore deps entries on auto-generated directories.
2391 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082392
Daniel Cheng4dcdb6b2017-04-13 08:30:172393 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2394 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2395
2396 added_deps = new_deps.difference(old_deps)
2397
[email protected]2b438d62013-11-14 17:54:142398 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172399 for added_dep in added_deps:
2400 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2401 continue
2402 # Assume that a rule that ends in .h is a rule for a specific file.
2403 if added_dep.endswith('.h'):
2404 results.add(added_dep)
2405 else:
2406 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082407 return results
2408
2409
[email protected]e871964c2013-05-13 14:14:552410def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2411 """When a dependency prefixed with + is added to a DEPS file, we
2412 want to make sure that the change is reviewed by an OWNER of the
2413 target file or directory, to avoid layering violations from being
2414 introduced. This check verifies that this happens.
2415 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172416 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242417
2418 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492419 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242420 for f in input_api.AffectedFiles(include_deletes=False,
2421 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552422 filename = input_api.os_path.basename(f.LocalPath())
2423 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172424 virtual_depended_on_files.update(_CalculateAddedDeps(
2425 input_api.os_path,
2426 '\n'.join(f.OldContents()),
2427 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552428
[email protected]e871964c2013-05-13 14:14:552429 if not virtual_depended_on_files:
2430 return []
2431
2432 if input_api.is_committing:
2433 if input_api.tbr:
2434 return [output_api.PresubmitNotifyResult(
2435 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272436 if input_api.dry_run:
2437 return [output_api.PresubmitNotifyResult(
2438 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552439 if not input_api.change.issue:
2440 return [output_api.PresubmitError(
2441 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402442 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552443 output = output_api.PresubmitError
2444 else:
2445 output = output_api.PresubmitNotifyResult
2446
2447 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502448 owner_email, reviewers = (
2449 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2450 input_api,
2451 owners_db.email_regexp,
2452 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552453
2454 owner_email = owner_email or input_api.change.author_email
2455
[email protected]de4f7d22013-05-23 14:27:462456 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512457 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462458 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552459 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2460 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412461
2462 # We strip the /DEPS part that was added by
2463 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2464 # directory.
2465 def StripDeps(path):
2466 start_deps = path.rfind('/DEPS')
2467 if start_deps != -1:
2468 return path[:start_deps]
2469 else:
2470 return path
2471 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552472 for path in missing_files]
2473
2474 if unapproved_dependencies:
2475 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152476 output('You need LGTM from owners of depends-on paths in DEPS that were '
2477 'modified in this CL:\n %s' %
2478 '\n '.join(sorted(unapproved_dependencies)))]
2479 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2480 output_list.append(output(
2481 'Suggested missing target path OWNERS:\n %s' %
2482 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552483 return output_list
2484
2485 return []
2486
2487
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492488# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402489def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492490 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402491 black_list = (_EXCLUDED_PATHS +
2492 _TEST_CODE_EXCLUDED_PATHS +
2493 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042494 (r"^base[\\/]logging\.h$",
2495 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222496 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042497 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2498 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2499 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122500 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182501 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152502 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032503 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152504 r"^chrome[\\/]chrome_cleaner[\\/].*",
2505 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2506 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042507 r"^chromecast[\\/]",
2508 r"^cloud_print[\\/]",
2509 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482510 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052511 r"^components[\\/]media_control[\\/]renderer[\\/]"
2512 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042513 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462514 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042515 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462516 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042517 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252518 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042519 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2520 r"^courgette[\\/]courgette_tool\.cc$",
2521 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272522 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002523 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332524 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042525 r"^ipc[\\/]ipc_logging\.cc$",
2526 r"^native_client_sdk[\\/]",
2527 r"^remoting[\\/]base[\\/]logging\.h$",
2528 r"^remoting[\\/]host[\\/].*",
2529 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062530 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332531 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042532 r"^tools[\\/]",
2533 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2534 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:372535 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2536 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2537 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402538 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492539 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402540
thomasanderson625d3932017-03-29 07:16:582541 log_info = set([])
2542 printf = set([])
[email protected]85218562013-11-22 07:41:402543
2544 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582545 for _, line in f.ChangedContents():
2546 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2547 log_info.add(f.LocalPath())
2548 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2549 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372550
thomasanderson625d3932017-03-29 07:16:582551 if input_api.re.search(r"\bprintf\(", line):
2552 printf.add(f.LocalPath())
2553 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2554 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402555
2556 if log_info:
2557 return [output_api.PresubmitError(
2558 'These files spam the console log with LOG(INFO):',
2559 items=log_info)]
2560 if printf:
2561 return [output_api.PresubmitError(
2562 'These files spam the console log with printf/fprintf:',
2563 items=printf)]
2564 return []
2565
2566
[email protected]49aa76a2013-12-04 06:59:162567def _CheckForAnonymousVariables(input_api, output_api):
2568 """These types are all expected to hold locks while in scope and
2569 so should never be anonymous (which causes them to be immediately
2570 destroyed)."""
2571 they_who_must_be_named = [
2572 'base::AutoLock',
2573 'base::AutoReset',
2574 'base::AutoUnlock',
2575 'SkAutoAlphaRestore',
2576 'SkAutoBitmapShaderInstall',
2577 'SkAutoBlitterChoose',
2578 'SkAutoBounderCommit',
2579 'SkAutoCallProc',
2580 'SkAutoCanvasRestore',
2581 'SkAutoCommentBlock',
2582 'SkAutoDescriptor',
2583 'SkAutoDisableDirectionCheck',
2584 'SkAutoDisableOvalCheck',
2585 'SkAutoFree',
2586 'SkAutoGlyphCache',
2587 'SkAutoHDC',
2588 'SkAutoLockColors',
2589 'SkAutoLockPixels',
2590 'SkAutoMalloc',
2591 'SkAutoMaskFreeImage',
2592 'SkAutoMutexAcquire',
2593 'SkAutoPathBoundsUpdate',
2594 'SkAutoPDFRelease',
2595 'SkAutoRasterClipValidate',
2596 'SkAutoRef',
2597 'SkAutoTime',
2598 'SkAutoTrace',
2599 'SkAutoUnref',
2600 ]
2601 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2602 # bad: base::AutoLock(lock.get());
2603 # not bad: base::AutoLock lock(lock.get());
2604 bad_pattern = input_api.re.compile(anonymous)
2605 # good: new base::AutoLock(lock.get())
2606 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2607 errors = []
2608
2609 for f in input_api.AffectedFiles():
2610 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2611 continue
2612 for linenum, line in f.ChangedContents():
2613 if bad_pattern.search(line) and not good_pattern.search(line):
2614 errors.append('%s:%d' % (f.LocalPath(), linenum))
2615
2616 if errors:
2617 return [output_api.PresubmitError(
2618 'These lines create anonymous variables that need to be named:',
2619 items=errors)]
2620 return []
2621
2622
Peter Kasting4844e46e2018-02-23 07:27:102623def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532624 # Returns whether |template_str| is of the form <T, U...> for some types T
2625 # and U. Assumes that |template_str| is already in the form <...>.
2626 def HasMoreThanOneArg(template_str):
2627 # Level of <...> nesting.
2628 nesting = 0
2629 for c in template_str:
2630 if c == '<':
2631 nesting += 1
2632 elif c == '>':
2633 nesting -= 1
2634 elif c == ',' and nesting == 1:
2635 return True
2636 return False
2637
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492638 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102639 sources = lambda affected_file: input_api.FilterSourceFile(
2640 affected_file,
2641 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2642 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492643 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552644
2645 # Pattern to capture a single "<...>" block of template arguments. It can
2646 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2647 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2648 # latter would likely require counting that < and > match, which is not
2649 # expressible in regular languages. Should the need arise, one can introduce
2650 # limited counting (matching up to a total number of nesting depth), which
2651 # should cover all practical cases for already a low nesting limit.
2652 template_arg_pattern = (
2653 r'<[^>]*' # Opening block of <.
2654 r'>([^<]*>)?') # Closing block of >.
2655 # Prefix expressing that whatever follows is not already inside a <...>
2656 # block.
2657 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102658 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552659 not_inside_template_arg_pattern
2660 + r'\bstd::unique_ptr'
2661 + template_arg_pattern
2662 + r'\(\)')
2663
2664 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2665 template_arg_no_array_pattern = (
2666 r'<[^>]*[^]]' # Opening block of <.
2667 r'>([^(<]*[^]]>)?') # Closing block of >.
2668 # Prefix saying that what follows is the start of an expression.
2669 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2670 # Suffix saying that what follows are call parentheses with a non-empty list
2671 # of arguments.
2672 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532673 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552674 return_construct_pattern = input_api.re.compile(
2675 start_of_expr_pattern
2676 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532677 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552678 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532679 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552680 + nonempty_arg_list_pattern)
2681
Vaclav Brozek851d9602018-04-04 16:13:052682 problems_constructor = []
2683 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102684 for f in input_api.AffectedSourceFiles(sources):
2685 for line_number, line in f.ChangedContents():
2686 # Disallow:
2687 # return std::unique_ptr<T>(foo);
2688 # bar = std::unique_ptr<T>(foo);
2689 # But allow:
2690 # return std::unique_ptr<T[]>(foo);
2691 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532692 # And also allow cases when the second template argument is present. Those
2693 # cases cannot be handled by std::make_unique:
2694 # return std::unique_ptr<T, U>(foo);
2695 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052696 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532697 return_construct_result = return_construct_pattern.search(line)
2698 if return_construct_result and not HasMoreThanOneArg(
2699 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052700 problems_constructor.append(
2701 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102702 # Disallow:
2703 # std::unique_ptr<T>()
2704 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052705 problems_nullptr.append(
2706 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2707
2708 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162709 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052710 errors.append(output_api.PresubmitError(
2711 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162712 problems_nullptr))
2713 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052714 errors.append(output_api.PresubmitError(
2715 'The following files use explicit std::unique_ptr constructor.'
2716 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162717 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102718 return errors
2719
2720
[email protected]999261d2014-03-03 20:08:082721def _CheckUserActionUpdate(input_api, output_api):
2722 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522723 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082724 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522725 # If actions.xml is already included in the changelist, the PRESUBMIT
2726 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082727 return []
2728
[email protected]999261d2014-03-03 20:08:082729 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2730 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522731 current_actions = None
[email protected]999261d2014-03-03 20:08:082732 for f in input_api.AffectedFiles(file_filter=file_filter):
2733 for line_num, line in f.ChangedContents():
2734 match = input_api.re.search(action_re, line)
2735 if match:
[email protected]2f92dec2014-03-07 19:21:522736 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2737 # loaded only once.
2738 if not current_actions:
2739 with open('tools/metrics/actions/actions.xml') as actions_f:
2740 current_actions = actions_f.read()
2741 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082742 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522743 action = 'name="{0}"'.format(action_name)
2744 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082745 return [output_api.PresubmitPromptWarning(
2746 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522747 'tools/metrics/actions/actions.xml. Please run '
2748 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082749 % (f.LocalPath(), line_num, action_name))]
2750 return []
2751
2752
Daniel Cheng13ca61a882017-08-25 15:11:252753def _ImportJSONCommentEater(input_api):
2754 import sys
2755 sys.path = sys.path + [input_api.os_path.join(
2756 input_api.PresubmitLocalPath(),
2757 'tools', 'json_comment_eater')]
2758 import json_comment_eater
2759 return json_comment_eater
2760
2761
[email protected]99171a92014-06-03 08:44:472762def _GetJSONParseError(input_api, filename, eat_comments=True):
2763 try:
2764 contents = input_api.ReadFile(filename)
2765 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252766 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132767 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472768
2769 input_api.json.loads(contents)
2770 except ValueError as e:
2771 return e
2772 return None
2773
2774
2775def _GetIDLParseError(input_api, filename):
2776 try:
2777 contents = input_api.ReadFile(filename)
2778 idl_schema = input_api.os_path.join(
2779 input_api.PresubmitLocalPath(),
2780 'tools', 'json_schema_compiler', 'idl_schema.py')
2781 process = input_api.subprocess.Popen(
2782 [input_api.python_executable, idl_schema],
2783 stdin=input_api.subprocess.PIPE,
2784 stdout=input_api.subprocess.PIPE,
2785 stderr=input_api.subprocess.PIPE,
2786 universal_newlines=True)
2787 (_, error) = process.communicate(input=contents)
2788 return error or None
2789 except ValueError as e:
2790 return e
2791
2792
2793def _CheckParseErrors(input_api, output_api):
2794 """Check that IDL and JSON files do not contain syntax errors."""
2795 actions = {
2796 '.idl': _GetIDLParseError,
2797 '.json': _GetJSONParseError,
2798 }
[email protected]99171a92014-06-03 08:44:472799 # Most JSON files are preprocessed and support comments, but these do not.
2800 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042801 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472802 ]
2803 # Only run IDL checker on files in these directories.
2804 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042805 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2806 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472807 ]
2808
2809 def get_action(affected_file):
2810 filename = affected_file.LocalPath()
2811 return actions.get(input_api.os_path.splitext(filename)[1])
2812
[email protected]99171a92014-06-03 08:44:472813 def FilterFile(affected_file):
2814 action = get_action(affected_file)
2815 if not action:
2816 return False
2817 path = affected_file.LocalPath()
2818
Erik Staab2dd72b12020-04-16 15:03:402819 if _MatchesFile(input_api,
2820 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2821 path):
[email protected]99171a92014-06-03 08:44:472822 return False
2823
2824 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162825 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472826 return False
2827 return True
2828
2829 results = []
2830 for affected_file in input_api.AffectedFiles(
2831 file_filter=FilterFile, include_deletes=False):
2832 action = get_action(affected_file)
2833 kwargs = {}
2834 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162835 _MatchesFile(input_api, json_no_comments_patterns,
2836 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472837 kwargs['eat_comments'] = False
2838 parse_error = action(input_api,
2839 affected_file.AbsoluteLocalPath(),
2840 **kwargs)
2841 if parse_error:
2842 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2843 (affected_file.LocalPath(), parse_error)))
2844 return results
2845
2846
[email protected]760deea2013-12-10 19:33:492847def _CheckJavaStyle(input_api, output_api):
2848 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472849 import sys
[email protected]760deea2013-12-10 19:33:492850 original_sys_path = sys.path
2851 try:
2852 sys.path = sys.path + [input_api.os_path.join(
2853 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2854 import checkstyle
2855 finally:
2856 # Restore sys.path to what it was before.
2857 sys.path = original_sys_path
2858
2859 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092860 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512861 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492862
2863
Nate Fischerdfd9812e2019-07-18 22:03:002864def _CheckPythonDevilInit(input_api, output_api):
2865 """Checks to make sure devil is initialized correctly in python scripts."""
2866 script_common_initialize_pattern = input_api.re.compile(
2867 r'script_common\.InitializeEnvironment\(')
2868 devil_env_config_initialize = input_api.re.compile(
2869 r'devil_env\.config\.Initialize\(')
2870
2871 errors = []
2872
2873 sources = lambda affected_file: input_api.FilterSourceFile(
2874 affected_file,
2875 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2876 (r'^build[\\/]android[\\/]devil_chromium\.py',
2877 r'^third_party[\\/].*',)),
2878 white_list=[r'.*\.py$'])
2879
2880 for f in input_api.AffectedSourceFiles(sources):
2881 for line_num, line in f.ChangedContents():
2882 if (script_common_initialize_pattern.search(line) or
2883 devil_env_config_initialize.search(line)):
2884 errors.append("%s:%d" % (f.LocalPath(), line_num))
2885
2886 results = []
2887
2888 if errors:
2889 results.append(output_api.PresubmitError(
2890 'Devil initialization should always be done using '
2891 'devil_chromium.Initialize() in the chromium project, to use better '
2892 'defaults for dependencies (ex. up-to-date version of adb).',
2893 errors))
2894
2895 return results
2896
2897
Sean Kau46e29bc2017-08-28 16:31:162898def _MatchesFile(input_api, patterns, path):
2899 for pattern in patterns:
2900 if input_api.re.search(pattern, path):
2901 return True
2902 return False
2903
2904
Daniel Cheng7052cdf2017-11-21 19:23:292905def _GetOwnersFilesToCheckForIpcOwners(input_api):
2906 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172907
Daniel Cheng7052cdf2017-11-21 19:23:292908 Returns:
2909 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2910 contain to cover IPC-related files with noparent reviewer rules.
2911 """
2912 # Whether or not a file affects IPC is (mostly) determined by a simple list
2913 # of filename patterns.
dchenge07de812016-06-20 19:27:172914 file_patterns = [
palmerb19a0932017-01-24 04:00:312915 # Legacy IPC:
dchenge07de812016-06-20 19:27:172916 '*_messages.cc',
2917 '*_messages*.h',
2918 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312919 # Mojo IPC:
dchenge07de812016-06-20 19:27:172920 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472921 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172922 '*_struct_traits*.*',
2923 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312924 '*.typemap',
2925 # Android native IPC:
2926 '*.aidl',
2927 # Blink uses a different file naming convention:
2928 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472929 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172930 '*StructTraits*.*',
2931 '*TypeConverter*.*',
2932 ]
2933
scottmg7a6ed5ba2016-11-04 18:22:042934 # These third_party directories do not contain IPCs, but contain files
2935 # matching the above patterns, which trigger false positives.
2936 exclude_paths = [
2937 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162938 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232939 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292940 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542941 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162942 # These files are just used to communicate between class loaders running
2943 # in the same process.
2944 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572945 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2946
scottmg7a6ed5ba2016-11-04 18:22:042947 ]
2948
dchenge07de812016-06-20 19:27:172949 # Dictionary mapping an OWNERS file path to Patterns.
2950 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2951 # rules ) to a PatternEntry.
2952 # PatternEntry is a dictionary with two keys:
2953 # - 'files': the files that are matched by this pattern
2954 # - 'rules': the per-file rules needed for this pattern
2955 # For example, if we expect OWNERS file to contain rules for *.mojom and
2956 # *_struct_traits*.*, Patterns might look like this:
2957 # {
2958 # '*.mojom': {
2959 # 'files': ...,
2960 # 'rules': [
2961 # 'per-file *.mojom=set noparent',
2962 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2963 # ],
2964 # },
2965 # '*_struct_traits*.*': {
2966 # 'files': ...,
2967 # 'rules': [
2968 # 'per-file *_struct_traits*.*=set noparent',
2969 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2970 # ],
2971 # },
2972 # }
2973 to_check = {}
2974
Daniel Cheng13ca61a882017-08-25 15:11:252975 def AddPatternToCheck(input_file, pattern):
2976 owners_file = input_api.os_path.join(
2977 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2978 if owners_file not in to_check:
2979 to_check[owners_file] = {}
2980 if pattern not in to_check[owners_file]:
2981 to_check[owners_file][pattern] = {
2982 'files': [],
2983 'rules': [
2984 'per-file %s=set noparent' % pattern,
2985 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2986 ]
2987 }
Vaclav Brozekd5de76a2018-03-17 07:57:502988 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252989
dchenge07de812016-06-20 19:27:172990 # Iterate through the affected files to see what we actually need to check
2991 # for. We should only nag patch authors about per-file rules if a file in that
2992 # directory would match that pattern. If a directory only contains *.mojom
2993 # files and no *_messages*.h files, we should only nag about rules for
2994 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252995 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262996 # Manifest files don't have a strong naming convention. Instead, try to find
2997 # affected .cc and .h files which look like they contain a manifest
2998 # definition.
2999 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
3000 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
3001 if (manifest_pattern.search(f.LocalPath()) and not
3002 test_manifest_pattern.search(f.LocalPath())):
3003 # We expect all actual service manifest files to contain at least one
3004 # qualified reference to service_manager::Manifest.
3005 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:253006 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:173007 for pattern in file_patterns:
3008 if input_api.fnmatch.fnmatch(
3009 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043010 skip = False
3011 for exclude in exclude_paths:
3012 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3013 skip = True
3014 break
3015 if skip:
3016 continue
Daniel Cheng13ca61a882017-08-25 15:11:253017 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173018 break
3019
Daniel Cheng7052cdf2017-11-21 19:23:293020 return to_check
3021
3022
Wez17c66962020-04-29 15:26:033023def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3024 """Adds OWNERS files to check for correct Fuchsia security owners."""
3025
3026 file_patterns = [
3027 # Component specifications.
3028 '*.cml', # Component Framework v2.
3029 '*.cmx', # Component Framework v1.
3030
3031 # Fuchsia IDL protocol specifications.
3032 '*.fidl',
3033 ]
3034
3035 def AddPatternToCheck(input_file, pattern):
3036 owners_file = input_api.os_path.join(
3037 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3038 if owners_file not in to_check:
3039 to_check[owners_file] = {}
3040 if pattern not in to_check[owners_file]:
3041 to_check[owners_file][pattern] = {
3042 'files': [],
3043 'rules': [
3044 'per-file %s=set noparent' % pattern,
3045 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3046 ]
3047 }
3048 to_check[owners_file][pattern]['files'].append(input_file)
3049
3050 # Iterate through the affected files to see what we actually need to check
3051 # for. We should only nag patch authors about per-file rules if a file in that
3052 # directory would match that pattern.
3053 for f in input_api.AffectedFiles(include_deletes=False):
3054 for pattern in file_patterns:
3055 if input_api.fnmatch.fnmatch(
3056 input_api.os_path.basename(f.LocalPath()), pattern):
3057 AddPatternToCheck(f, pattern)
3058 break
3059
3060 return to_check
3061
3062
3063def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293064 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3065 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033066 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293067
3068 if to_check:
3069 # If there are any OWNERS files to check, there are IPC-related changes in
3070 # this CL. Auto-CC the review list.
3071 output_api.AppendCC('[email protected]')
3072
3073 # Go through the OWNERS files to check, filtering out rules that are already
3074 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173075 for owners_file, patterns in to_check.iteritems():
3076 try:
3077 with file(owners_file) as f:
3078 lines = set(f.read().splitlines())
3079 for entry in patterns.itervalues():
3080 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3081 ]
3082 except IOError:
3083 # No OWNERS file, so all the rules are definitely missing.
3084 continue
3085
3086 # All the remaining lines weren't found in OWNERS files, so emit an error.
3087 errors = []
3088 for owners_file, patterns in to_check.iteritems():
3089 missing_lines = []
3090 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503091 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173092 missing_lines.extend(entry['rules'])
3093 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3094 if missing_lines:
3095 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053096 'Because of the presence of files:\n%s\n\n'
3097 '%s needs the following %d lines added:\n\n%s' %
3098 ('\n'.join(files), owners_file, len(missing_lines),
3099 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173100
3101 results = []
3102 if errors:
vabrf5ce3bf92016-07-11 14:52:413103 if input_api.is_committing:
3104 output = output_api.PresubmitError
3105 else:
3106 output = output_api.PresubmitPromptWarning
3107 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593108 'Found OWNERS files that need to be updated for IPC security ' +
3109 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173110 long_text='\n\n'.join(errors)))
3111
3112 return results
3113
3114
Robert Sesek2c905332020-05-06 23:17:133115def _GetFilesUsingSecurityCriticalFunctions(input_api):
3116 """Checks affected files for changes to security-critical calls. This
3117 function checks the full change diff, to catch both additions/changes
3118 and removals.
3119
3120 Returns a dict keyed by file name, and the value is a set of detected
3121 functions.
3122 """
3123 # Map of function pretty name (displayed in an error) to the pattern to
3124 # match it with.
3125 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373126 'content::GetServiceSandboxType<>()':
3127 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133128 }
3129 _PATTERNS_TO_CHECK = {
3130 k: input_api.re.compile(v)
3131 for k, v in _PATTERNS_TO_CHECK.items()
3132 }
3133
3134 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3135 files_to_functions = {}
3136 for f in input_api.AffectedFiles():
3137 diff = f.GenerateScmDiff()
3138 for line in diff.split('\n'):
3139 # Not using just RightHandSideLines() because removing a
3140 # call to a security-critical function can be just as important
3141 # as adding or changing the arguments.
3142 if line.startswith('-') or (line.startswith('+') and
3143 not line.startswith('++')):
3144 for name, pattern in _PATTERNS_TO_CHECK.items():
3145 if pattern.search(line):
3146 path = f.LocalPath()
3147 if not path in files_to_functions:
3148 files_to_functions[path] = set()
3149 files_to_functions[path].add(name)
3150 return files_to_functions
3151
3152
3153def _CheckSecurityChanges(input_api, output_api):
3154 """Checks that changes involving security-critical functions are reviewed
3155 by the security team.
3156 """
3157 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3158 if len(files_to_functions):
3159 owners_db = input_api.owners_db
3160 owner_email, reviewers = (
3161 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3162 input_api,
3163 owners_db.email_regexp,
3164 approval_needed=input_api.is_committing))
3165
3166 # Load the OWNERS file for security changes.
3167 owners_file = 'ipc/SECURITY_OWNERS'
3168 security_owners = owners_db.owners_rooted_at_file(owners_file)
3169
3170 has_security_owner = any([owner in reviewers for owner in security_owners])
3171 if not has_security_owner:
3172 msg = 'The following files change calls to security-sensive functions\n' \
3173 'that need to be reviewed by {}.\n'.format(owners_file)
3174 for path, names in files_to_functions.items():
3175 msg += ' {}\n'.format(path)
3176 for name in names:
3177 msg += ' {}\n'.format(name)
3178 msg += '\n'
3179
3180 if input_api.is_committing:
3181 output = output_api.PresubmitError
3182 else:
3183 output = output_api.PresubmitNotifyResult
3184 return [output(msg)]
3185
3186 return []
3187
3188
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263189def _CheckSetNoParent(input_api, output_api):
3190 """Checks that set noparent is only used together with an OWNERS file in
3191 //build/OWNERS.setnoparent (see also
3192 //docs/code_reviews.md#owners-files-details)
3193 """
3194 errors = []
3195
3196 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3197 allowed_owners_files = set()
3198 with open(allowed_owners_files_file, 'r') as f:
3199 for line in f:
3200 line = line.strip()
3201 if not line or line.startswith('#'):
3202 continue
3203 allowed_owners_files.add(line)
3204
3205 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3206
3207 for f in input_api.AffectedFiles(include_deletes=False):
3208 if not f.LocalPath().endswith('OWNERS'):
3209 continue
3210
3211 found_owners_files = set()
3212 found_set_noparent_lines = dict()
3213
3214 # Parse the OWNERS file.
3215 for lineno, line in enumerate(f.NewContents(), 1):
3216 line = line.strip()
3217 if line.startswith('set noparent'):
3218 found_set_noparent_lines[''] = lineno
3219 if line.startswith('file://'):
3220 if line in allowed_owners_files:
3221 found_owners_files.add('')
3222 if line.startswith('per-file'):
3223 match = per_file_pattern.match(line)
3224 if match:
3225 glob = match.group(1).strip()
3226 directive = match.group(2).strip()
3227 if directive == 'set noparent':
3228 found_set_noparent_lines[glob] = lineno
3229 if directive.startswith('file://'):
3230 if directive in allowed_owners_files:
3231 found_owners_files.add(glob)
3232
3233 # Check that every set noparent line has a corresponding file:// line
3234 # listed in build/OWNERS.setnoparent.
3235 for set_noparent_line in found_set_noparent_lines:
3236 if set_noparent_line in found_owners_files:
3237 continue
3238 errors.append(' %s:%d' % (f.LocalPath(),
3239 found_set_noparent_lines[set_noparent_line]))
3240
3241 results = []
3242 if errors:
3243 if input_api.is_committing:
3244 output = output_api.PresubmitError
3245 else:
3246 output = output_api.PresubmitPromptWarning
3247 results.append(output(
3248 'Found the following "set noparent" restrictions in OWNERS files that '
3249 'do not include owners from build/OWNERS.setnoparent:',
3250 long_text='\n\n'.join(errors)))
3251 return results
3252
3253
jbriance9e12f162016-11-25 07:57:503254def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313255 """Checks that added or removed lines in non third party affected
3256 header files do not lead to new useless class or struct forward
3257 declaration.
jbriance9e12f162016-11-25 07:57:503258 """
3259 results = []
3260 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3261 input_api.re.MULTILINE)
3262 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3263 input_api.re.MULTILINE)
3264 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313265 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193266 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493267 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313268 continue
3269
jbriance9e12f162016-11-25 07:57:503270 if not f.LocalPath().endswith('.h'):
3271 continue
3272
3273 contents = input_api.ReadFile(f)
3274 fwd_decls = input_api.re.findall(class_pattern, contents)
3275 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3276
3277 useless_fwd_decls = []
3278 for decl in fwd_decls:
3279 count = sum(1 for _ in input_api.re.finditer(
3280 r'\b%s\b' % input_api.re.escape(decl), contents))
3281 if count == 1:
3282 useless_fwd_decls.append(decl)
3283
3284 if not useless_fwd_decls:
3285 continue
3286
3287 for line in f.GenerateScmDiff().splitlines():
3288 if (line.startswith('-') and not line.startswith('--') or
3289 line.startswith('+') and not line.startswith('++')):
3290 for decl in useless_fwd_decls:
3291 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3292 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243293 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503294 (f.LocalPath(), decl)))
3295 useless_fwd_decls.remove(decl)
3296
3297 return results
3298
Jinsong Fan91ebbbd2019-04-16 14:57:173299def _CheckAndroidDebuggableBuild(input_api, output_api):
3300 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3301 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3302 this is a debuggable build of Android.
3303 """
3304 build_type_check_pattern = input_api.re.compile(
3305 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3306
3307 errors = []
3308
3309 sources = lambda affected_file: input_api.FilterSourceFile(
3310 affected_file,
3311 black_list=(_EXCLUDED_PATHS +
3312 _TEST_CODE_EXCLUDED_PATHS +
3313 input_api.DEFAULT_BLACK_LIST +
3314 (r"^android_webview[\\/]support_library[\\/]"
3315 "boundary_interfaces[\\/]",
3316 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3317 r'^third_party[\\/].*',
3318 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3319 r"webview[\\/]chromium[\\/]License.*",)),
3320 white_list=[r'.*\.java$'])
3321
3322 for f in input_api.AffectedSourceFiles(sources):
3323 for line_num, line in f.ChangedContents():
3324 if build_type_check_pattern.search(line):
3325 errors.append("%s:%d" % (f.LocalPath(), line_num))
3326
3327 results = []
3328
3329 if errors:
3330 results.append(output_api.PresubmitPromptWarning(
3331 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3332 ' Please use BuildInfo.isDebugAndroid() instead.',
3333 errors))
3334
3335 return results
jbriance9e12f162016-11-25 07:57:503336
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493337# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293338def _CheckAndroidToastUsage(input_api, output_api):
3339 """Checks that code uses org.chromium.ui.widget.Toast instead of
3340 android.widget.Toast (Chromium Toast doesn't force hardware
3341 acceleration on low-end devices, saving memory).
3342 """
3343 toast_import_pattern = input_api.re.compile(
3344 r'^import android\.widget\.Toast;$')
3345
3346 errors = []
3347
3348 sources = lambda affected_file: input_api.FilterSourceFile(
3349 affected_file,
3350 black_list=(_EXCLUDED_PATHS +
3351 _TEST_CODE_EXCLUDED_PATHS +
3352 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043353 (r'^chromecast[\\/].*',
3354 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493355 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293356
3357 for f in input_api.AffectedSourceFiles(sources):
3358 for line_num, line in f.ChangedContents():
3359 if toast_import_pattern.search(line):
3360 errors.append("%s:%d" % (f.LocalPath(), line_num))
3361
3362 results = []
3363
3364 if errors:
3365 results.append(output_api.PresubmitError(
3366 'android.widget.Toast usage is detected. Android toasts use hardware'
3367 ' acceleration, and can be\ncostly on low-end devices. Please use'
3368 ' org.chromium.ui.widget.Toast instead.\n'
3369 'Contact [email protected] if you have any questions.',
3370 errors))
3371
3372 return results
3373
3374
dgnaa68d5e2015-06-10 10:08:223375def _CheckAndroidCrLogUsage(input_api, output_api):
3376 """Checks that new logs using org.chromium.base.Log:
3377 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513378 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223379 """
pkotwicza1dd0b002016-05-16 14:41:043380
torne89540622017-03-24 19:41:303381 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043382 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303383 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043384 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303385 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043386 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3387 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093388 # The customtabs_benchmark is a small app that does not depend on Chromium
3389 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043390 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043391 ]
3392
dgnaa68d5e2015-06-10 10:08:223393 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123394 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3395 class_in_base_pattern = input_api.re.compile(
3396 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3397 has_some_log_import_pattern = input_api.re.compile(
3398 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223399 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553400 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223401 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463402 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553403 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223404
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463405 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493406 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043407 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123408
dgnaa68d5e2015-06-10 10:08:223409 tag_decl_errors = []
3410 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123411 tag_errors = []
dgn38736db2015-09-18 19:20:513412 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123413 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223414
3415 for f in input_api.AffectedSourceFiles(sources):
3416 file_content = input_api.ReadFile(f)
3417 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223418 # Per line checks
dgn87d9fb62015-06-12 09:15:123419 if (cr_log_import_pattern.search(file_content) or
3420 (class_in_base_pattern.search(file_content) and
3421 not has_some_log_import_pattern.search(file_content))):
3422 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223423 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553424 if rough_log_decl_pattern.search(line):
3425 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223426
3427 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123428 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223429 if match:
3430 has_modified_logs = True
3431
3432 # Make sure it uses "TAG"
3433 if not match.group('tag') == 'TAG':
3434 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123435 else:
3436 # Report non cr Log function calls in changed lines
3437 for line_num, line in f.ChangedContents():
3438 if log_call_pattern.search(line):
3439 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223440
3441 # Per file checks
3442 if has_modified_logs:
3443 # Make sure the tag is using the "cr" prefix and is not too long
3444 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513445 tag_name = match.group('name') if match else None
3446 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223447 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513448 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223449 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513450 elif '.' in tag_name:
3451 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223452
3453 results = []
3454 if tag_decl_errors:
3455 results.append(output_api.PresubmitPromptWarning(
3456 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513457 '"private static final String TAG = "<package tag>".\n'
3458 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223459 tag_decl_errors))
3460
3461 if tag_length_errors:
3462 results.append(output_api.PresubmitError(
3463 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513464 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223465 tag_length_errors))
3466
3467 if tag_errors:
3468 results.append(output_api.PresubmitPromptWarning(
3469 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3470 tag_errors))
3471
dgn87d9fb62015-06-12 09:15:123472 if util_log_errors:
dgn4401aa52015-04-29 16:26:173473 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123474 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3475 util_log_errors))
3476
dgn38736db2015-09-18 19:20:513477 if tag_with_dot_errors:
3478 results.append(output_api.PresubmitPromptWarning(
3479 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3480 tag_with_dot_errors))
3481
dgn4401aa52015-04-29 16:26:173482 return results
3483
3484
Yoland Yanb92fa522017-08-28 17:37:063485def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3486 """Checks that junit.framework.* is no longer used."""
3487 deprecated_junit_framework_pattern = input_api.re.compile(
3488 r'^import junit\.framework\..*;',
3489 input_api.re.MULTILINE)
3490 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493491 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063492 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133493 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063494 for line_num, line in f.ChangedContents():
3495 if deprecated_junit_framework_pattern.search(line):
3496 errors.append("%s:%d" % (f.LocalPath(), line_num))
3497
3498 results = []
3499 if errors:
3500 results.append(output_api.PresubmitError(
3501 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3502 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3503 ' if you have any question.', errors))
3504 return results
3505
3506
3507def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3508 """Checks that if new Java test classes have inheritance.
3509 Either the new test class is JUnit3 test or it is a JUnit4 test class
3510 with a base class, either case is undesirable.
3511 """
3512 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3513
3514 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493515 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063516 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133517 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063518 if not f.OldContents():
3519 class_declaration_start_flag = False
3520 for line_num, line in f.ChangedContents():
3521 if class_declaration_pattern.search(line):
3522 class_declaration_start_flag = True
3523 if class_declaration_start_flag and ' extends ' in line:
3524 errors.append('%s:%d' % (f.LocalPath(), line_num))
3525 if '{' in line:
3526 class_declaration_start_flag = False
3527
3528 results = []
3529 if errors:
3530 results.append(output_api.PresubmitPromptWarning(
3531 'The newly created files include Test classes that inherits from base'
3532 ' class. Please do not use inheritance in JUnit4 tests or add new'
3533 ' JUnit3 tests. Contact [email protected] if you have any'
3534 ' questions.', errors))
3535 return results
3536
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203537
yolandyan45001472016-12-21 21:12:423538def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3539 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3540 deprecated_annotation_import_pattern = input_api.re.compile(
3541 r'^import android\.test\.suitebuilder\.annotation\..*;',
3542 input_api.re.MULTILINE)
3543 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493544 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423545 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133546 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423547 for line_num, line in f.ChangedContents():
3548 if deprecated_annotation_import_pattern.search(line):
3549 errors.append("%s:%d" % (f.LocalPath(), line_num))
3550
3551 results = []
3552 if errors:
3553 results.append(output_api.PresubmitError(
3554 'Annotations in android.test.suitebuilder.annotation have been'
3555 ' deprecated since API level 24. Please use android.support.test.filters'
3556 ' from //third_party/android_support_test_runner:runner_java instead.'
3557 ' Contact [email protected] if you have any questions.', errors))
3558 return results
3559
3560
agrieve7b6479d82015-10-07 14:24:223561def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3562 """Checks if MDPI assets are placed in a correct directory."""
3563 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3564 ('/res/drawable/' in f.LocalPath() or
3565 '/res/drawable-ldrtl/' in f.LocalPath()))
3566 errors = []
3567 for f in input_api.AffectedFiles(include_deletes=False,
3568 file_filter=file_filter):
3569 errors.append(' %s' % f.LocalPath())
3570
3571 results = []
3572 if errors:
3573 results.append(output_api.PresubmitError(
3574 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3575 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3576 '/res/drawable-ldrtl/.\n'
3577 'Contact [email protected] if you have questions.', errors))
3578 return results
3579
3580
Nate Fischer535972b2017-09-16 01:06:183581def _CheckAndroidWebkitImports(input_api, output_api):
3582 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353583 android.webview.ValueCallback except in the WebView glue layer
3584 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183585 """
3586 valuecallback_import_pattern = input_api.re.compile(
3587 r'^import android\.webkit\.ValueCallback;$')
3588
3589 errors = []
3590
3591 sources = lambda affected_file: input_api.FilterSourceFile(
3592 affected_file,
3593 black_list=(_EXCLUDED_PATHS +
3594 _TEST_CODE_EXCLUDED_PATHS +
3595 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353596 (r'^android_webview[\\/]glue[\\/].*',
3597 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493598 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183599
3600 for f in input_api.AffectedSourceFiles(sources):
3601 for line_num, line in f.ChangedContents():
3602 if valuecallback_import_pattern.search(line):
3603 errors.append("%s:%d" % (f.LocalPath(), line_num))
3604
3605 results = []
3606
3607 if errors:
3608 results.append(output_api.PresubmitError(
3609 'android.webkit.ValueCallback usage is detected outside of the glue'
3610 ' layer. To stay compatible with the support library, android.webkit.*'
3611 ' classes should only be used inside the glue layer and'
3612 ' org.chromium.base.Callback should be used instead.',
3613 errors))
3614
3615 return results
3616
3617
Becky Zhou7c69b50992018-12-10 19:37:573618def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3619 """Checks Android XML styles """
3620 import sys
3621 original_sys_path = sys.path
3622 try:
3623 sys.path = sys.path + [input_api.os_path.join(
3624 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3625 import checkxmlstyle
3626 finally:
3627 # Restore sys.path to what it was before.
3628 sys.path = original_sys_path
3629
3630 if is_check_on_upload:
3631 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3632 else:
3633 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3634
3635
agrievef32bcc72016-04-04 14:57:403636class PydepsChecker(object):
3637 def __init__(self, input_api, pydeps_files):
3638 self._file_cache = {}
3639 self._input_api = input_api
3640 self._pydeps_files = pydeps_files
3641
3642 def _LoadFile(self, path):
3643 """Returns the list of paths within a .pydeps file relative to //."""
3644 if path not in self._file_cache:
3645 with open(path) as f:
3646 self._file_cache[path] = f.read()
3647 return self._file_cache[path]
3648
3649 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3650 """Returns an interable of paths within the .pydep, relativized to //."""
3651 os_path = self._input_api.os_path
3652 pydeps_dir = os_path.dirname(pydeps_path)
3653 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3654 if not l.startswith('*'))
3655 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3656
3657 def _CreateFilesToPydepsMap(self):
3658 """Returns a map of local_path -> list_of_pydeps."""
3659 ret = {}
3660 for pydep_local_path in self._pydeps_files:
3661 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3662 ret.setdefault(path, []).append(pydep_local_path)
3663 return ret
3664
3665 def ComputeAffectedPydeps(self):
3666 """Returns an iterable of .pydeps files that might need regenerating."""
3667 affected_pydeps = set()
3668 file_to_pydeps_map = None
3669 for f in self._input_api.AffectedFiles(include_deletes=True):
3670 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463671 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3672 # subrepositories. We can't figure out which files change, so re-check
3673 # all files.
3674 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383675 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3676 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403677 return self._pydeps_files
3678 elif local_path.endswith('.pydeps'):
3679 if local_path in self._pydeps_files:
3680 affected_pydeps.add(local_path)
3681 elif local_path.endswith('.py'):
3682 if file_to_pydeps_map is None:
3683 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3684 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3685 return affected_pydeps
3686
3687 def DetermineIfStale(self, pydeps_path):
3688 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413689 import difflib
John Budorick47ca3fe2018-02-10 00:53:103690 import os
3691
agrievef32bcc72016-04-04 14:57:403692 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033693 if old_pydeps_data:
3694 cmd = old_pydeps_data[1][1:].strip()
3695 old_contents = old_pydeps_data[2:]
3696 else:
3697 # A default cmd that should work in most cases (as long as pydeps filename
3698 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3699 # file is empty/new.
3700 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3701 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3702 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103703 env = dict(os.environ)
3704 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403705 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103706 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413707 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033708 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413709 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403710
3711
Tibor Goldschwendt360793f72019-06-25 18:23:493712def _ParseGclientArgs():
3713 args = {}
3714 with open('build/config/gclient_args.gni', 'r') as f:
3715 for line in f:
3716 line = line.strip()
3717 if not line or line.startswith('#'):
3718 continue
3719 attribute, value = line.split('=')
3720 args[attribute.strip()] = value.strip()
3721 return args
3722
3723
agrievef32bcc72016-04-04 14:57:403724def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3725 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403726 # This check is for Python dependency lists (.pydeps files), and involves
3727 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3728 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283729 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003730 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493731 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403732 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403733 results = []
3734 # First, check for new / deleted .pydeps.
3735 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033736 # Check whether we are running the presubmit check for a file in src.
3737 # f.LocalPath is relative to repo (src, or internal repo).
3738 # os_path.exists is relative to src repo.
3739 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3740 # to src and we can conclude that the pydeps is in src.
3741 if input_api.os_path.exists(f.LocalPath()):
3742 if f.LocalPath().endswith('.pydeps'):
3743 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3744 results.append(output_api.PresubmitError(
3745 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3746 'remove %s' % f.LocalPath()))
3747 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3748 results.append(output_api.PresubmitError(
3749 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3750 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403751
3752 if results:
3753 return results
3754
Mohamed Heikal7cd4d8312020-06-16 16:49:403755 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3756 affected_pydeps = set(checker.ComputeAffectedPydeps())
3757 affected_android_pydeps = affected_pydeps.intersection(
3758 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3759 if affected_android_pydeps and not is_android:
3760 results.append(output_api.PresubmitPromptOrNotify(
3761 'You have changed python files that may affect pydeps for android\n'
3762 'specific scripts. However, the relevant presumbit check cannot be\n'
3763 'run because you are not using an Android checkout. To validate that\n'
3764 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3765 'use the android-internal-presubmit optional trybot.\n'
3766 'Possibly stale pydeps files:\n{}'.format(
3767 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403768
Mohamed Heikal7cd4d8312020-06-16 16:49:403769 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3770 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403771 try:
phajdan.jr0d9878552016-11-04 10:49:413772 result = checker.DetermineIfStale(pydep_path)
3773 if result:
3774 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403775 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413776 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3777 'To regenerate, run:\n\n %s' %
3778 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403779 except input_api.subprocess.CalledProcessError as error:
3780 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3781 long_text=error.output)]
3782
3783 return results
3784
3785
glidere61efad2015-02-18 17:39:433786def _CheckSingletonInHeaders(input_api, output_api):
3787 """Checks to make sure no header files have |Singleton<|."""
3788 def FileFilter(affected_file):
3789 # It's ok for base/memory/singleton.h to have |Singleton<|.
3790 black_list = (_EXCLUDED_PATHS +
3791 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043792 (r"^base[\\/]memory[\\/]singleton\.h$",
3793 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473794 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433795 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3796
sergeyu34d21222015-09-16 00:11:443797 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433798 files = []
3799 for f in input_api.AffectedSourceFiles(FileFilter):
3800 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3801 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3802 contents = input_api.ReadFile(f)
3803 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243804 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433805 pattern.search(line)):
3806 files.append(f)
3807 break
3808
3809 if files:
yolandyandaabc6d2016-04-18 18:29:393810 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443811 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433812 'Please move them to an appropriate source file so that the ' +
3813 'template gets instantiated in a single compilation unit.',
3814 files) ]
3815 return []
3816
3817
[email protected]fd20b902014-05-09 02:14:533818_DEPRECATED_CSS = [
3819 # Values
3820 ( "-webkit-box", "flex" ),
3821 ( "-webkit-inline-box", "inline-flex" ),
3822 ( "-webkit-flex", "flex" ),
3823 ( "-webkit-inline-flex", "inline-flex" ),
3824 ( "-webkit-min-content", "min-content" ),
3825 ( "-webkit-max-content", "max-content" ),
3826
3827 # Properties
3828 ( "-webkit-background-clip", "background-clip" ),
3829 ( "-webkit-background-origin", "background-origin" ),
3830 ( "-webkit-background-size", "background-size" ),
3831 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443832 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533833
3834 # Functions
3835 ( "-webkit-gradient", "gradient" ),
3836 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3837 ( "-webkit-linear-gradient", "linear-gradient" ),
3838 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3839 ( "-webkit-radial-gradient", "radial-gradient" ),
3840 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3841]
3842
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203843
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493844# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243845def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533846 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253847 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343848 documentation and iOS CSS for dom distiller
3849 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253850 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533851 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493852 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253853 black_list = (_EXCLUDED_PATHS +
3854 _TEST_CODE_EXCLUDED_PATHS +
3855 input_api.DEFAULT_BLACK_LIST +
3856 (r"^chrome/common/extensions/docs",
3857 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343858 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443859 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253860 r"^native_client_sdk"))
3861 file_filter = lambda f: input_api.FilterSourceFile(
3862 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533863 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3864 for line_num, line in fpath.ChangedContents():
3865 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023866 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533867 results.append(output_api.PresubmitError(
3868 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3869 (fpath.LocalPath(), line_num, deprecated_value, value)))
3870 return results
3871
mohan.reddyf21db962014-10-16 12:26:473872
rlanday6802cf632017-05-30 17:48:363873def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363874 bad_files = {}
3875 for f in input_api.AffectedFiles(include_deletes=False):
3876 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493877 not f.LocalPath().startswith('third_party/blink') and
3878 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363879 continue
3880
Daniel Bratell65b033262019-04-23 08:17:063881 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363882 continue
3883
Vaclav Brozekd5de76a2018-03-17 07:57:503884 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363885 if "#include" in line and "../" in line]
3886 if not relative_includes:
3887 continue
3888 bad_files[f.LocalPath()] = relative_includes
3889
3890 if not bad_files:
3891 return []
3892
3893 error_descriptions = []
3894 for file_path, bad_lines in bad_files.iteritems():
3895 error_description = file_path
3896 for line in bad_lines:
3897 error_description += '\n ' + line
3898 error_descriptions.append(error_description)
3899
3900 results = []
3901 results.append(output_api.PresubmitError(
3902 'You added one or more relative #include paths (including "../").\n'
3903 'These shouldn\'t be used because they can be used to include headers\n'
3904 'from code that\'s not correctly specified as a dependency in the\n'
3905 'relevant BUILD.gn file(s).',
3906 error_descriptions))
3907
3908 return results
3909
Takeshi Yoshinoe387aa32017-08-02 13:16:133910
Daniel Bratell65b033262019-04-23 08:17:063911def _CheckForCcIncludes(input_api, output_api):
3912 """Check that nobody tries to include a cc file. It's a relatively
3913 common error which results in duplicate symbols in object
3914 files. This may not always break the build until someone later gets
3915 very confusing linking errors."""
3916 results = []
3917 for f in input_api.AffectedFiles(include_deletes=False):
3918 # We let third_party code do whatever it wants
3919 if (f.LocalPath().startswith('third_party') and
3920 not f.LocalPath().startswith('third_party/blink') and
3921 not f.LocalPath().startswith('third_party\\blink')):
3922 continue
3923
3924 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3925 continue
3926
3927 for _, line in f.ChangedContents():
3928 if line.startswith('#include "'):
3929 included_file = line.split('"')[1]
3930 if _IsCPlusPlusFile(input_api, included_file):
3931 # The most common naming for external files with C++ code,
3932 # apart from standard headers, is to call them foo.inc, but
3933 # Chromium sometimes uses foo-inc.cc so allow that as well.
3934 if not included_file.endswith(('.h', '-inc.cc')):
3935 results.append(output_api.PresubmitError(
3936 'Only header files or .inc files should be included in other\n'
3937 'C++ files. Compiling the contents of a cc file more than once\n'
3938 'will cause duplicate information in the build which may later\n'
3939 'result in strange link_errors.\n' +
3940 f.LocalPath() + ':\n ' +
3941 line))
3942
3943 return results
3944
3945
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203946def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3947 if not isinstance(key, ast.Str):
3948 return 'Key at line %d must be a string literal' % key.lineno
3949 if not isinstance(value, ast.Dict):
3950 return 'Value at line %d must be a dict' % value.lineno
3951 if len(value.keys) != 1:
3952 return 'Dict at line %d must have single entry' % value.lineno
3953 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3954 return (
3955 'Entry at line %d must have a string literal \'filepath\' as key' %
3956 value.lineno)
3957 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133958
Takeshi Yoshinoe387aa32017-08-02 13:16:133959
Sergey Ulanov4af16052018-11-08 02:41:463960def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203961 if not isinstance(key, ast.Str):
3962 return 'Key at line %d must be a string literal' % key.lineno
3963 if not isinstance(value, ast.List):
3964 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463965 for element in value.elts:
3966 if not isinstance(element, ast.Str):
3967 return 'Watchlist elements on line %d is not a string' % key.lineno
3968 if not email_regex.match(element.s):
3969 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3970 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203971 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133972
Takeshi Yoshinoe387aa32017-08-02 13:16:133973
Sergey Ulanov4af16052018-11-08 02:41:463974def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203975 mismatch_template = (
3976 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3977 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133978
Sergey Ulanov4af16052018-11-08 02:41:463979 email_regex = input_api.re.compile(
3980 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3981
3982 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203983 i = 0
3984 last_key = ''
3985 while True:
3986 if i >= len(wd_dict.keys):
3987 if i >= len(w_dict.keys):
3988 return None
3989 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3990 elif i >= len(w_dict.keys):
3991 return (
3992 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133993
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203994 wd_key = wd_dict.keys[i]
3995 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133996
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203997 result = _CheckWatchlistDefinitionsEntrySyntax(
3998 wd_key, wd_dict.values[i], ast)
3999 if result is not None:
4000 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:134001
Sergey Ulanov4af16052018-11-08 02:41:464002 result = _CheckWatchlistsEntrySyntax(
4003 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204004 if result is not None:
4005 return 'Bad entry in WATCHLISTS dict: %s' % result
4006
4007 if wd_key.s != w_key.s:
4008 return mismatch_template % (
4009 '%s at line %d' % (wd_key.s, wd_key.lineno),
4010 '%s at line %d' % (w_key.s, w_key.lineno))
4011
4012 if wd_key.s < last_key:
4013 return (
4014 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4015 (wd_key.lineno, w_key.lineno))
4016 last_key = wd_key.s
4017
4018 i = i + 1
4019
4020
Sergey Ulanov4af16052018-11-08 02:41:464021def _CheckWATCHLISTSSyntax(expression, input_api):
4022 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204023 if not isinstance(expression, ast.Expression):
4024 return 'WATCHLISTS file must contain a valid expression'
4025 dictionary = expression.body
4026 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4027 return 'WATCHLISTS file must have single dict with exactly two entries'
4028
4029 first_key = dictionary.keys[0]
4030 first_value = dictionary.values[0]
4031 second_key = dictionary.keys[1]
4032 second_value = dictionary.values[1]
4033
4034 if (not isinstance(first_key, ast.Str) or
4035 first_key.s != 'WATCHLIST_DEFINITIONS' or
4036 not isinstance(first_value, ast.Dict)):
4037 return (
4038 'The first entry of the dict in WATCHLISTS file must be '
4039 'WATCHLIST_DEFINITIONS dict')
4040
4041 if (not isinstance(second_key, ast.Str) or
4042 second_key.s != 'WATCHLISTS' or
4043 not isinstance(second_value, ast.Dict)):
4044 return (
4045 'The second entry of the dict in WATCHLISTS file must be '
4046 'WATCHLISTS dict')
4047
Sergey Ulanov4af16052018-11-08 02:41:464048 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134049
4050
4051def _CheckWATCHLISTS(input_api, output_api):
4052 for f in input_api.AffectedFiles(include_deletes=False):
4053 if f.LocalPath() == 'WATCHLISTS':
4054 contents = input_api.ReadFile(f, 'r')
4055
4056 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204057 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134058 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204059 # Get an AST tree for it and scan the tree for detailed style checking.
4060 expression = input_api.ast.parse(
4061 contents, filename='WATCHLISTS', mode='eval')
4062 except ValueError as e:
4063 return [output_api.PresubmitError(
4064 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4065 except SyntaxError as e:
4066 return [output_api.PresubmitError(
4067 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4068 except TypeError as e:
4069 return [output_api.PresubmitError(
4070 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134071
Sergey Ulanov4af16052018-11-08 02:41:464072 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204073 if result is not None:
4074 return [output_api.PresubmitError(result)]
4075 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134076
4077 return []
4078
4079
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194080def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4081 """Checks that newly added header files have corresponding GN changes.
4082 Note that this is only a heuristic. To be precise, run script:
4083 build/check_gn_headers.py.
4084 """
4085
4086 def headers(f):
4087 return input_api.FilterSourceFile(
4088 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4089
4090 new_headers = []
4091 for f in input_api.AffectedSourceFiles(headers):
4092 if f.Action() != 'A':
4093 continue
4094 new_headers.append(f.LocalPath())
4095
4096 def gn_files(f):
4097 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4098
4099 all_gn_changed_contents = ''
4100 for f in input_api.AffectedSourceFiles(gn_files):
4101 for _, line in f.ChangedContents():
4102 all_gn_changed_contents += line
4103
4104 problems = []
4105 for header in new_headers:
4106 basename = input_api.os_path.basename(header)
4107 if basename not in all_gn_changed_contents:
4108 problems.append(header)
4109
4110 if problems:
4111 return [output_api.PresubmitPromptWarning(
4112 'Missing GN changes for new header files', items=sorted(problems),
4113 long_text='Please double check whether newly added header files need '
4114 'corresponding changes in gn or gni files.\nThis checking is only a '
4115 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4116 'Read https://crbug.com/661774 for more info.')]
4117 return []
4118
4119
Michael Giuffridad3bc8672018-10-25 22:48:024120def _CheckCorrectProductNameInMessages(input_api, output_api):
4121 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4122
4123 This assumes we won't intentionally reference one product from the other
4124 product.
4125 """
4126 all_problems = []
4127 test_cases = [{
4128 "filename_postfix": "google_chrome_strings.grd",
4129 "correct_name": "Chrome",
4130 "incorrect_name": "Chromium",
4131 }, {
4132 "filename_postfix": "chromium_strings.grd",
4133 "correct_name": "Chromium",
4134 "incorrect_name": "Chrome",
4135 }]
4136
4137 for test_case in test_cases:
4138 problems = []
4139 filename_filter = lambda x: x.LocalPath().endswith(
4140 test_case["filename_postfix"])
4141
4142 # Check each new line. Can yield false positives in multiline comments, but
4143 # easier than trying to parse the XML because messages can have nested
4144 # children, and associating message elements with affected lines is hard.
4145 for f in input_api.AffectedSourceFiles(filename_filter):
4146 for line_num, line in f.ChangedContents():
4147 if "<message" in line or "<!--" in line or "-->" in line:
4148 continue
4149 if test_case["incorrect_name"] in line:
4150 problems.append(
4151 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4152
4153 if problems:
4154 message = (
4155 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4156 % (test_case["correct_name"], test_case["correct_name"],
4157 test_case["incorrect_name"]))
4158 all_problems.append(
4159 output_api.PresubmitPromptWarning(message, items=problems))
4160
4161 return all_problems
4162
4163
Dirk Pranke3c18a382019-03-15 01:07:514164def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4165 # TODO(crbug.com/941824): We need to make sure the entries in
4166 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4167 # so that users of //buildtools in other projects get the same tooling
4168 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4169 # support to gclient, we can eliminate the duplication and delete
4170 # this presubmit check.
4171
4172 # Update this regexp if new revisions are added to the files.
4173 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264174 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514175
4176 # If a user is changing one revision, they need to change the same
4177 # line in both files. This means that any given change should contain
4178 # exactly the same list of changed lines that match the regexps. The
4179 # replace(' ', '') call allows us to ignore whitespace changes to the
4180 # lines. The 'long_text' parameter to the error will contain the
4181 # list of changed lines in both files, which should make it easy enough
4182 # to spot the error without going overboard in this implementation.
4183 revs_changes = {
4184 'DEPS': {},
4185 'buildtools/DEPS': {},
4186 }
4187 long_text = ''
4188
4189 for f in input_api.AffectedFiles(
4190 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4191 for line_num, line in f.ChangedContents():
4192 if rev_regexp.search(line):
4193 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4194 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4195
4196 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4197 return [output_api.PresubmitError(
4198 'Change buildtools revisions in sync in both //DEPS and '
4199 '//buildtools/DEPS.', long_text=long_text + '\n')]
4200 else:
4201 return []
4202
4203
Daniel Bratell93eb6c62019-04-29 20:13:364204def _CheckForTooLargeFiles(input_api, output_api):
4205 """Avoid large files, especially binary files, in the repository since
4206 git doesn't scale well for those. They will be in everyone's repo
4207 clones forever, forever making Chromium slower to clone and work
4208 with."""
4209
4210 # Uploading files to cloud storage is not trivial so we don't want
4211 # to set the limit too low, but the upper limit for "normal" large
4212 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4213 # anything over 20 MB is exceptional.
4214 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4215
4216 too_large_files = []
4217 for f in input_api.AffectedFiles():
4218 # Check both added and modified files (but not deleted files).
4219 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384220 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364221 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4222 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4223
4224 if too_large_files:
4225 message = (
4226 'Do not commit large files to git since git scales badly for those.\n' +
4227 'Instead put the large files in cloud storage and use DEPS to\n' +
4228 'fetch them.\n' + '\n'.join(too_large_files)
4229 )
4230 return [output_api.PresubmitError(
4231 'Too large files found in commit', long_text=message + '\n')]
4232 else:
4233 return []
4234
Max Morozb47503b2019-08-08 21:03:274235
4236def _CheckFuzzTargets(input_api, output_api):
4237 """Checks specific for fuzz target sources."""
4238 EXPORTED_SYMBOLS = [
4239 'LLVMFuzzerInitialize',
4240 'LLVMFuzzerCustomMutator',
4241 'LLVMFuzzerCustomCrossOver',
4242 'LLVMFuzzerMutate',
4243 ]
4244
4245 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4246
4247 def FilterFile(affected_file):
4248 """Ignore libFuzzer source code."""
4249 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4250 black_list = r"^third_party[\\/]libFuzzer"
4251
4252 return input_api.FilterSourceFile(
4253 affected_file,
4254 white_list=[white_list],
4255 black_list=[black_list])
4256
4257 files_with_missing_header = []
4258 for f in input_api.AffectedSourceFiles(FilterFile):
4259 contents = input_api.ReadFile(f, 'r')
4260 if REQUIRED_HEADER in contents:
4261 continue
4262
4263 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4264 files_with_missing_header.append(f.LocalPath())
4265
4266 if not files_with_missing_header:
4267 return []
4268
4269 long_text = (
4270 'If you define any of the libFuzzer optional functions (%s), it is '
4271 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4272 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4273 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4274 'to access command line arguments passed to the fuzzer. Instead, prefer '
4275 'static initialization and shared resources as documented in '
4276 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4277 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4278 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4279 )
4280
4281 return [output_api.PresubmitPromptWarning(
4282 message="Missing '%s' in:" % REQUIRED_HEADER,
4283 items=files_with_missing_header,
4284 long_text=long_text)]
4285
4286
Mohamed Heikald048240a2019-11-12 16:57:374287def _CheckNewImagesWarning(input_api, output_api):
4288 """
4289 Warns authors who add images into the repo to make sure their images are
4290 optimized before committing.
4291 """
4292 images_added = False
4293 image_paths = []
4294 errors = []
4295 filter_lambda = lambda x: input_api.FilterSourceFile(
4296 x,
4297 black_list=(('(?i).*test', r'.*\/junit\/')
4298 + input_api.DEFAULT_BLACK_LIST),
4299 white_list=[r'.*\/(drawable|mipmap)' ]
4300 )
4301 for f in input_api.AffectedFiles(
4302 include_deletes=False, file_filter=filter_lambda):
4303 local_path = f.LocalPath().lower()
4304 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4305 images_added = True
4306 image_paths.append(f)
4307 if images_added:
4308 errors.append(output_api.PresubmitPromptWarning(
4309 'It looks like you are trying to commit some images. If these are '
4310 'non-test-only images, please make sure to read and apply the tips in '
4311 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4312 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4313 'FYI only and will not block your CL on the CQ.', image_paths))
4314 return errors
4315
4316
dgnaa68d5e2015-06-10 10:08:224317def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574318 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224319 results = []
dgnaa68d5e2015-06-10 10:08:224320 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174321 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224322 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294323 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064324 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4325 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424326 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184327 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574328 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374329 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154330 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574331 return results
4332
4333def _AndroidSpecificOnCommitChecks(input_api, output_api):
4334 """Groups commit checks that target android code."""
4335 results = []
4336 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224337 return results
4338
Chris Hall59f8d0c72020-05-01 07:31:194339# TODO(chrishall): could we additionally match on any path owned by
4340# ui/accessibility/OWNERS ?
4341_ACCESSIBILITY_PATHS = (
4342 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4343 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4344 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4345 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4346 r"^content[\\/]browser[\\/]accessibility[\\/]",
4347 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4348 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4349 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4350 r"^ui[\\/]accessibility[\\/]",
4351 r"^ui[\\/]views[\\/]accessibility[\\/]",
4352)
4353
4354def _CheckAccessibilityRelnotesField(input_api, output_api):
4355 """Checks that commits to accessibility code contain an AX-Relnotes field in
4356 their commit message."""
4357 def FileFilter(affected_file):
4358 paths = _ACCESSIBILITY_PATHS
4359 return input_api.FilterSourceFile(affected_file, white_list=paths)
4360
4361 # Only consider changes affecting accessibility paths.
4362 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4363 return []
4364
Akihiro Ota08108e542020-05-20 15:30:534365 # AX-Relnotes can appear in either the description or the footer.
4366 # When searching the description, require 'AX-Relnotes:' to appear at the
4367 # beginning of a line.
4368 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4369 description_has_relnotes = any(ax_regex.match(line)
4370 for line in input_api.change.DescriptionText().lower().splitlines())
4371
4372 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4373 'AX-Relnotes', [])
4374 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194375 return []
4376
4377 # TODO(chrishall): link to Relnotes documentation in message.
4378 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4379 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4380 "user-facing changes"
4381 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4382 "user-facing effects"
4383 "\n if this is confusing or annoying then please contact members "
4384 "of ui/accessibility/OWNERS.")
4385
4386 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224387
[email protected]22c9bd72011-03-27 16:47:394388def _CommonChecks(input_api, output_api):
4389 """Checks common to both upload and commit."""
4390 results = []
4391 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384392 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544393 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084394
4395 author = input_api.change.author_email
4396 if author and author not in _KNOWN_ROBOTS:
4397 results.extend(
4398 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4399
Chris Hall59f8d0c72020-05-01 07:31:194400 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194401 results.extend(
[email protected]760deea2013-12-10 19:33:494402 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234403 results.extend(
4404 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544405 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184406 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344407 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524408 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224409 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444410 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594411 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314412 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064413 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124414 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184415 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224416 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304417 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494418 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034419 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494420 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444421 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294422 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274423 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074424 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544425 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444426 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394427 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554428 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044429 results.extend(
4430 input_api.canned_checks.CheckChangeHasNoTabs(
4431 input_api,
4432 output_api,
4433 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404434 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164435 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084436 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244437 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474438 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044439 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054440 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144441 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234442 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434443 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404444 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154445 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034446 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134447 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264448 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504449 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364450 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064451 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134452 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434453 results.extend(input_api.RunTests(
4454 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264455 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124456 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024457 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514458 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364459 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004460 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514461 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244462
Vaclav Brozekcdc7defb2018-03-20 09:54:354463 for f in input_api.AffectedFiles():
4464 path, name = input_api.os_path.split(f.LocalPath())
4465 if name == 'PRESUBMIT.py':
4466 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004467 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4468 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074469 # The PRESUBMIT.py file (and the directory containing it) might
4470 # have been affected by being moved or removed, so only try to
4471 # run the tests if they still exist.
4472 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4473 input_api, output_api, full_path,
4474 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394475 return results
[email protected]1f7b4172010-01-28 01:17:344476
[email protected]b337cb5b2011-01-23 21:24:054477
[email protected]b8079ae4a2012-12-05 19:56:494478def _CheckPatchFiles(input_api, output_api):
4479 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4480 if f.LocalPath().endswith(('.orig', '.rej'))]
4481 if problems:
4482 return [output_api.PresubmitError(
4483 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034484 else:
4485 return []
[email protected]b8079ae4a2012-12-05 19:56:494486
4487
Kent Tamura5a8755d2017-06-29 23:37:074488def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214489 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4490 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4491 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074492 include_re = input_api.re.compile(
4493 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4494 extension_re = input_api.re.compile(r'\.[a-z]+$')
4495 errors = []
4496 for f in input_api.AffectedFiles():
4497 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4498 continue
4499 found_line_number = None
4500 found_macro = None
4501 for line_num, line in f.ChangedContents():
4502 match = macro_re.search(line)
4503 if match:
4504 found_line_number = line_num
4505 found_macro = match.group(2)
4506 break
4507 if not found_line_number:
4508 continue
4509
4510 found_include = False
4511 for line in f.NewContents():
4512 if include_re.search(line):
4513 found_include = True
4514 break
4515 if found_include:
4516 continue
4517
4518 if not f.LocalPath().endswith('.h'):
4519 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4520 try:
4521 content = input_api.ReadFile(primary_header_path, 'r')
4522 if include_re.search(content):
4523 continue
4524 except IOError:
4525 pass
4526 errors.append('%s:%d %s macro is used without including build/'
4527 'build_config.h.'
4528 % (f.LocalPath(), found_line_number, found_macro))
4529 if errors:
4530 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4531 return []
4532
4533
[email protected]b00342e7f2013-03-26 16:21:544534def _DidYouMeanOSMacro(bad_macro):
4535 try:
4536 return {'A': 'OS_ANDROID',
4537 'B': 'OS_BSD',
4538 'C': 'OS_CHROMEOS',
4539 'F': 'OS_FREEBSD',
4540 'L': 'OS_LINUX',
4541 'M': 'OS_MACOSX',
4542 'N': 'OS_NACL',
4543 'O': 'OS_OPENBSD',
4544 'P': 'OS_POSIX',
4545 'S': 'OS_SOLARIS',
4546 'W': 'OS_WIN'}[bad_macro[3].upper()]
4547 except KeyError:
4548 return ''
4549
4550
4551def _CheckForInvalidOSMacrosInFile(input_api, f):
4552 """Check for sensible looking, totally invalid OS macros."""
4553 preprocessor_statement = input_api.re.compile(r'^\s*#')
4554 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4555 results = []
4556 for lnum, line in f.ChangedContents():
4557 if preprocessor_statement.search(line):
4558 for match in os_macro.finditer(line):
4559 if not match.group(1) in _VALID_OS_MACROS:
4560 good = _DidYouMeanOSMacro(match.group(1))
4561 did_you_mean = ' (did you mean %s?)' % good if good else ''
4562 results.append(' %s:%d %s%s' % (f.LocalPath(),
4563 lnum,
4564 match.group(1),
4565 did_you_mean))
4566 return results
4567
4568
4569def _CheckForInvalidOSMacros(input_api, output_api):
4570 """Check all affected files for invalid OS macros."""
4571 bad_macros = []
tzik3f295992018-12-04 20:32:234572 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474573 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544574 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4575
4576 if not bad_macros:
4577 return []
4578
4579 return [output_api.PresubmitError(
4580 'Possibly invalid OS macro[s] found. Please fix your code\n'
4581 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4582
lliabraa35bab3932014-10-01 12:16:444583
4584def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4585 """Check all affected files for invalid "if defined" macros."""
4586 ALWAYS_DEFINED_MACROS = (
4587 "TARGET_CPU_PPC",
4588 "TARGET_CPU_PPC64",
4589 "TARGET_CPU_68K",
4590 "TARGET_CPU_X86",
4591 "TARGET_CPU_ARM",
4592 "TARGET_CPU_MIPS",
4593 "TARGET_CPU_SPARC",
4594 "TARGET_CPU_ALPHA",
4595 "TARGET_IPHONE_SIMULATOR",
4596 "TARGET_OS_EMBEDDED",
4597 "TARGET_OS_IPHONE",
4598 "TARGET_OS_MAC",
4599 "TARGET_OS_UNIX",
4600 "TARGET_OS_WIN32",
4601 )
4602 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4603 results = []
4604 for lnum, line in f.ChangedContents():
4605 for match in ifdef_macro.finditer(line):
4606 if match.group(1) in ALWAYS_DEFINED_MACROS:
4607 always_defined = ' %s is always defined. ' % match.group(1)
4608 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4609 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4610 lnum,
4611 always_defined,
4612 did_you_mean))
4613 return results
4614
4615
4616def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4617 """Check all affected files for invalid "if defined" macros."""
4618 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054619 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444620 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054621 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214622 continue
lliabraa35bab3932014-10-01 12:16:444623 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4624 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4625
4626 if not bad_macros:
4627 return []
4628
4629 return [output_api.PresubmitError(
4630 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4631 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4632 bad_macros)]
4633
4634
mlamouria82272622014-09-16 18:45:044635def _CheckForIPCRules(input_api, output_api):
4636 """Check for same IPC rules described in
4637 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4638 """
4639 base_pattern = r'IPC_ENUM_TRAITS\('
4640 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4641 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4642
4643 problems = []
4644 for f in input_api.AffectedSourceFiles(None):
4645 local_path = f.LocalPath()
4646 if not local_path.endswith('.h'):
4647 continue
4648 for line_number, line in f.ChangedContents():
4649 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4650 problems.append(
4651 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4652
4653 if problems:
4654 return [output_api.PresubmitPromptWarning(
4655 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4656 else:
4657 return []
4658
[email protected]b00342e7f2013-03-26 16:21:544659
Stephen Martinis97a394142018-06-07 23:06:054660def _CheckForLongPathnames(input_api, output_api):
4661 """Check to make sure no files being submitted have long paths.
4662 This causes issues on Windows.
4663 """
4664 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194665 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054666 local_path = f.LocalPath()
4667 # Windows has a path limit of 260 characters. Limit path length to 200 so
4668 # that we have some extra for the prefix on dev machines and the bots.
4669 if len(local_path) > 200:
4670 problems.append(local_path)
4671
4672 if problems:
4673 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4674 else:
4675 return []
4676
4677
Daniel Bratell8ba52722018-03-02 16:06:144678def _CheckForIncludeGuards(input_api, output_api):
4679 """Check that header files have proper guards against multiple inclusion.
4680 If a file should not have such guards (and it probably should) then it
4681 should include the string "no-include-guard-because-multiply-included".
4682 """
Daniel Bratell6a75baef62018-06-04 10:04:454683 def is_chromium_header_file(f):
4684 # We only check header files under the control of the Chromium
4685 # project. That is, those outside third_party apart from
4686 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324687 # We also exclude *_message_generator.h headers as they use
4688 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454689 file_with_path = input_api.os_path.normpath(f.LocalPath())
4690 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324691 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454692 (not file_with_path.startswith('third_party') or
4693 file_with_path.startswith(
4694 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144695
4696 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344697 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144698
4699 errors = []
4700
Daniel Bratell6a75baef62018-06-04 10:04:454701 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144702 guard_name = None
4703 guard_line_number = None
4704 seen_guard_end = False
4705
4706 file_with_path = input_api.os_path.normpath(f.LocalPath())
4707 base_file_name = input_api.os_path.splitext(
4708 input_api.os_path.basename(file_with_path))[0]
4709 upper_base_file_name = base_file_name.upper()
4710
4711 expected_guard = replace_special_with_underscore(
4712 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144713
4714 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574715 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4716 # are too many (1000+) files with slight deviations from the
4717 # coding style. The most important part is that the include guard
4718 # is there, and that it's unique, not the name so this check is
4719 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144720 #
4721 # As code becomes more uniform, this could be made stricter.
4722
4723 guard_name_pattern_list = [
4724 # Anything with the right suffix (maybe with an extra _).
4725 r'\w+_H__?',
4726
Daniel Bratell39b5b062018-05-16 18:09:574727 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144728 r'\w+_h',
4729
4730 # Anything including the uppercase name of the file.
4731 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4732 upper_base_file_name)) + r'\w*',
4733 ]
4734 guard_name_pattern = '|'.join(guard_name_pattern_list)
4735 guard_pattern = input_api.re.compile(
4736 r'#ifndef\s+(' + guard_name_pattern + ')')
4737
4738 for line_number, line in enumerate(f.NewContents()):
4739 if 'no-include-guard-because-multiply-included' in line:
4740 guard_name = 'DUMMY' # To not trigger check outside the loop.
4741 break
4742
4743 if guard_name is None:
4744 match = guard_pattern.match(line)
4745 if match:
4746 guard_name = match.group(1)
4747 guard_line_number = line_number
4748
Daniel Bratell39b5b062018-05-16 18:09:574749 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454750 # don't match the chromium style guide, but new files should
4751 # get it right.
4752 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574753 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144754 errors.append(output_api.PresubmitPromptWarning(
4755 'Header using the wrong include guard name %s' % guard_name,
4756 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574757 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144758 else:
4759 # The line after #ifndef should have a #define of the same name.
4760 if line_number == guard_line_number + 1:
4761 expected_line = '#define %s' % guard_name
4762 if line != expected_line:
4763 errors.append(output_api.PresubmitPromptWarning(
4764 'Missing "%s" for include guard' % expected_line,
4765 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4766 'Expected: %r\nGot: %r' % (expected_line, line)))
4767
4768 if not seen_guard_end and line == '#endif // %s' % guard_name:
4769 seen_guard_end = True
4770 elif seen_guard_end:
4771 if line.strip() != '':
4772 errors.append(output_api.PresubmitPromptWarning(
4773 'Include guard %s not covering the whole file' % (
4774 guard_name), [f.LocalPath()]))
4775 break # Nothing else to check and enough to warn once.
4776
4777 if guard_name is None:
4778 errors.append(output_api.PresubmitPromptWarning(
4779 'Missing include guard %s' % expected_guard,
4780 [f.LocalPath()],
4781 'Missing include guard in %s\n'
4782 'Recommended name: %s\n'
4783 'This check can be disabled by having the string\n'
4784 'no-include-guard-because-multiply-included in the header.' %
4785 (f.LocalPath(), expected_guard)))
4786
4787 return errors
4788
4789
mostynbb639aca52015-01-07 20:31:234790def _CheckForWindowsLineEndings(input_api, output_api):
4791 """Check source code and known ascii text files for Windows style line
4792 endings.
4793 """
earthdok1b5e0ee2015-03-10 15:19:104794 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234795
4796 file_inclusion_pattern = (
4797 known_text_files,
4798 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4799 )
4800
mostynbb639aca52015-01-07 20:31:234801 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534802 source_file_filter = lambda f: input_api.FilterSourceFile(
4803 f, white_list=file_inclusion_pattern, black_list=None)
4804 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504805 include_file = False
4806 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234807 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504808 include_file = True
4809 if include_file:
4810 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234811
4812 if problems:
4813 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4814 'these files to contain Windows style line endings?\n' +
4815 '\n'.join(problems))]
4816
4817 return []
4818
4819
Vaclav Brozekd5de76a2018-03-17 07:57:504820def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134821 """Checks that all source files use SYSLOG properly."""
4822 syslog_files = []
4823 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564824 for line_number, line in f.ChangedContents():
4825 if 'SYSLOG' in line:
4826 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4827
pastarmovj89f7ee12016-09-20 14:58:134828 if syslog_files:
4829 return [output_api.PresubmitPromptWarning(
4830 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4831 ' calls.\nFiles to check:\n', items=syslog_files)]
4832 return []
4833
4834
[email protected]1f7b4172010-01-28 01:17:344835def CheckChangeOnUpload(input_api, output_api):
4836 results = []
4837 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474838 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284839 results.extend(
jam93a6ee792017-02-08 23:59:224840 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194841 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224842 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134843 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164844 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534845 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194846 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274847 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544848 return results
[email protected]ca8d1982009-02-19 16:33:124849
4850
[email protected]1bfb8322014-04-23 01:02:414851def GetTryServerMasterForBot(bot):
4852 """Returns the Try Server master for the given bot.
4853
[email protected]0bb112362014-07-26 04:38:324854 It tries to guess the master from the bot name, but may still fail
4855 and return None. There is no longer a default master.
4856 """
4857 # Potentially ambiguous bot names are listed explicitly.
4858 master_map = {
tandriie5587792016-07-14 00:34:504859 'chromium_presubmit': 'master.tryserver.chromium.linux',
4860 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414861 }
[email protected]0bb112362014-07-26 04:38:324862 master = master_map.get(bot)
4863 if not master:
wnwen4fbaab82016-05-25 12:54:364864 if 'android' in bot:
tandriie5587792016-07-14 00:34:504865 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364866 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504867 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324868 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504869 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324870 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504871 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324872 return master
[email protected]1bfb8322014-04-23 01:02:414873
4874
[email protected]ca8d1982009-02-19 16:33:124875def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544876 results = []
[email protected]1f7b4172010-01-28 01:17:344877 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574878 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544879 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274880 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344881 input_api,
4882 output_api,
[email protected]2fdd1f362013-01-16 03:56:034883 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274884
jam93a6ee792017-02-08 23:59:224885 results.extend(
4886 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544887 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4888 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384889 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4890 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414891 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4892 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544893 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144894
4895
Rainhard Findlingfc31844c52020-05-15 09:58:264896def _CheckStrings(input_api, output_api):
4897 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024898 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4899 # footer is set to true.
4900 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264901 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024902 footer.lower()
4903 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264904 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024905
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144906 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264907 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144908 import sys
4909 from io import StringIO
4910
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144911 new_or_added_paths = set(f.LocalPath()
4912 for f in input_api.AffectedFiles()
4913 if (f.Action() == 'A' or f.Action() == 'M'))
4914 removed_paths = set(f.LocalPath()
4915 for f in input_api.AffectedFiles(include_deletes=True)
4916 if f.Action() == 'D')
4917
4918 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264919 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164920 if not affected_grds:
4921 return []
4922
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144923 affected_png_paths = [f.AbsoluteLocalPath()
4924 for f in input_api.AffectedFiles()
4925 if (f.LocalPath().endswith('.png'))]
4926
4927 # Check for screenshots. Developers can upload screenshots using
4928 # tools/translation/upload_screenshots.py which finds and uploads
4929 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4930 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4931 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4932 #
4933 # The logic here is as follows:
4934 #
4935 # - If the CL has a .png file under the screenshots directory for a grd
4936 # file, warn the developer. Actual images should never be checked into the
4937 # Chrome repo.
4938 #
4939 # - If the CL contains modified or new messages in grd files and doesn't
4940 # contain the corresponding .sha1 files, warn the developer to add images
4941 # and upload them via tools/translation/upload_screenshots.py.
4942 #
4943 # - If the CL contains modified or new messages in grd files and the
4944 # corresponding .sha1 files, everything looks good.
4945 #
4946 # - If the CL contains removed messages in grd files but the corresponding
4947 # .sha1 files aren't removed, warn the developer to remove them.
4948 unnecessary_screenshots = []
4949 missing_sha1 = []
4950 unnecessary_sha1_files = []
4951
Rainhard Findlingfc31844c52020-05-15 09:58:264952 # This checks verifies that the ICU syntax of messages this CL touched is
4953 # valid, and reports any found syntax errors.
4954 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4955 # without developers being aware of them. Later on, such ICU syntax errors
4956 # break message extraction for translation, hence would block Chromium
4957 # translations until they are fixed.
4958 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144959
4960 def _CheckScreenshotAdded(screenshots_dir, message_id):
4961 sha1_path = input_api.os_path.join(
4962 screenshots_dir, message_id + '.png.sha1')
4963 if sha1_path not in new_or_added_paths:
4964 missing_sha1.append(sha1_path)
4965
4966
4967 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4968 sha1_path = input_api.os_path.join(
4969 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034970 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144971 unnecessary_sha1_files.append(sha1_path)
4972
Rainhard Findlingfc31844c52020-05-15 09:58:264973
4974 def _ValidateIcuSyntax(text, level, signatures):
4975 """Validates ICU syntax of a text string.
4976
4977 Check if text looks similar to ICU and checks for ICU syntax correctness
4978 in this case. Reports various issues with ICU syntax and values of
4979 variants. Supports checking of nested messages. Accumulate information of
4980 each ICU messages found in the text for further checking.
4981
4982 Args:
4983 text: a string to check.
4984 level: a number of current nesting level.
4985 signatures: an accumulator, a list of tuple of (level, variable,
4986 kind, variants).
4987
4988 Returns:
4989 None if a string is not ICU or no issue detected.
4990 A tuple of (message, start index, end index) if an issue detected.
4991 """
4992 valid_types = {
4993 'plural': (frozenset(
4994 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4995 frozenset(['=1', 'other'])),
4996 'selectordinal': (frozenset(
4997 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4998 frozenset(['one', 'other'])),
4999 'select': (frozenset(), frozenset(['other'])),
5000 }
5001
5002 # Check if the message looks like an attempt to use ICU
5003 # plural. If yes - check if its syntax strictly matches ICU format.
5004 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5005 if not like:
5006 signatures.append((level, None, None, None))
5007 return
5008
5009 # Check for valid prefix and suffix
5010 m = re.match(
5011 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5012 r'(plural|selectordinal|select),\s*'
5013 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5014 if not m:
5015 return (('This message looks like an ICU plural, '
5016 'but does not follow ICU syntax.'), like.start(), like.end())
5017 starting, variable, kind, variant_pairs = m.groups()
5018 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5019 if depth:
5020 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5021 len(text))
5022 first = text[0]
5023 ending = text[last_pos:]
5024 if not starting:
5025 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5026 last_pos)
5027 if not ending or '}' not in ending:
5028 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5029 last_pos)
5030 elif first != '{':
5031 return (
5032 ('Invalid ICU format. Extra characters at the start of a complex '
5033 'message (go/icu-message-migration): "%s"') %
5034 starting, 0, len(starting))
5035 elif ending != '}':
5036 return (('Invalid ICU format. Extra characters at the end of a complex '
5037 'message (go/icu-message-migration): "%s"')
5038 % ending, last_pos - 1, len(text) - 1)
5039 if kind not in valid_types:
5040 return (('Unknown ICU message type %s. '
5041 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5042 known, required = valid_types[kind]
5043 defined_variants = set()
5044 for variant, variant_range, value, value_range in variants:
5045 start, end = variant_range
5046 if variant in defined_variants:
5047 return ('Variant "%s" is defined more than once' % variant,
5048 start, end)
5049 elif known and variant not in known:
5050 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5051 start, end)
5052 defined_variants.add(variant)
5053 # Check for nested structure
5054 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5055 if res:
5056 return (res[0], res[1] + value_range[0] + 1,
5057 res[2] + value_range[0] + 1)
5058 missing = required - defined_variants
5059 if missing:
5060 return ('Required variants missing: %s' % ', '.join(missing), 0,
5061 len(text))
5062 signatures.append((level, variable, kind, defined_variants))
5063
5064
5065 def _ParseIcuVariants(text, offset=0):
5066 """Parse variants part of ICU complex message.
5067
5068 Builds a tuple of variant names and values, as well as
5069 their offsets in the input string.
5070
5071 Args:
5072 text: a string to parse
5073 offset: additional offset to add to positions in the text to get correct
5074 position in the complete ICU string.
5075
5076 Returns:
5077 List of tuples, each tuple consist of four fields: variant name,
5078 variant name span (tuple of two integers), variant value, value
5079 span (tuple of two integers).
5080 """
5081 depth, start, end = 0, -1, -1
5082 variants = []
5083 key = None
5084 for idx, char in enumerate(text):
5085 if char == '{':
5086 if not depth:
5087 start = idx
5088 chunk = text[end + 1:start]
5089 key = chunk.strip()
5090 pos = offset + end + 1 + chunk.find(key)
5091 span = (pos, pos + len(key))
5092 depth += 1
5093 elif char == '}':
5094 if not depth:
5095 return variants, depth, offset + idx
5096 depth -= 1
5097 if not depth:
5098 end = idx
5099 variants.append((key, span, text[start:end + 1], (offset + start,
5100 offset + end + 1)))
5101 return variants, depth, offset + end + 1
5102
meacer8c0d3832019-12-26 21:46:165103 try:
5104 old_sys_path = sys.path
5105 sys.path = sys.path + [input_api.os_path.join(
5106 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5107 from helper import grd_helper
5108 finally:
5109 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110
5111 for f in affected_grds:
5112 file_path = f.LocalPath()
5113 old_id_to_msg_map = {}
5114 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385115 # Note that this code doesn't check if the file has been deleted. This is
5116 # OK because it only uses the old and new file contents and doesn't load
5117 # the file via its path.
5118 # It's also possible that a file's content refers to a renamed or deleted
5119 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5120 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5121 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122 if file_path.endswith('.grdp'):
5123 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585124 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395125 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585127 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395128 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129 else:
meacerff8a9b62019-12-10 19:43:585130 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145131 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585132 old_id_to_msg_map = grd_helper.GetGrdMessages(
5133 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585135 new_id_to_msg_map = grd_helper.GetGrdMessages(
5136 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145137
5138 # Compute added, removed and modified message IDs.
5139 old_ids = set(old_id_to_msg_map)
5140 new_ids = set(new_id_to_msg_map)
5141 added_ids = new_ids - old_ids
5142 removed_ids = old_ids - new_ids
5143 modified_ids = set([])
5144 for key in old_ids.intersection(new_ids):
5145 if (old_id_to_msg_map[key].FormatXml()
5146 != new_id_to_msg_map[key].FormatXml()):
5147 modified_ids.add(key)
5148
5149 grd_name, ext = input_api.os_path.splitext(
5150 input_api.os_path.basename(file_path))
5151 screenshots_dir = input_api.os_path.join(
5152 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5153
Rainhard Findlingfc31844c52020-05-15 09:58:265154 if run_screenshot_check:
5155 # Check the screenshot directory for .png files. Warn if there is any.
5156 for png_path in affected_png_paths:
5157 if png_path.startswith(screenshots_dir):
5158 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145159
Rainhard Findlingfc31844c52020-05-15 09:58:265160 for added_id in added_ids:
5161 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145162
Rainhard Findlingfc31844c52020-05-15 09:58:265163 for modified_id in modified_ids:
5164 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145165
Rainhard Findlingfc31844c52020-05-15 09:58:265166 for removed_id in removed_ids:
5167 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5168
5169 # Check new and changed strings for ICU syntax errors.
5170 for key in added_ids.union(modified_ids):
5171 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5172 err = _ValidateIcuSyntax(msg, 0, [])
5173 if err is not None:
5174 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145175
5176 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265177 if run_screenshot_check:
5178 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005179 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265180 'Do not include actual screenshots in the changelist. Run '
5181 'tools/translate/upload_screenshots.py to upload them instead:',
5182 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145183
Rainhard Findlingfc31844c52020-05-15 09:58:265184 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005185 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265186 'You are adding or modifying UI strings.\n'
5187 'To ensure the best translations, take screenshots of the relevant UI '
5188 '(https://g.co/chrome/translation) and add these files to your '
5189 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145190
Rainhard Findlingfc31844c52020-05-15 09:58:265191 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005192 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265193 'You removed strings associated with these files. Remove:',
5194 sorted(unnecessary_sha1_files)))
5195 else:
5196 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5197 'screenshots check.'))
5198
5199 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075200 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265201 'ICU syntax errors were found in the following strings (problems or '
5202 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145203
5204 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125205
5206
5207def _CheckTranslationExpectations(input_api, output_api,
5208 repo_root=None,
5209 translation_expectations_path=None,
5210 grd_files=None):
5211 import sys
5212 affected_grds = [f for f in input_api.AffectedFiles()
5213 if (f.LocalPath().endswith('.grd') or
5214 f.LocalPath().endswith('.grdp'))]
5215 if not affected_grds:
5216 return []
5217
5218 try:
5219 old_sys_path = sys.path
5220 sys.path = sys.path + [
5221 input_api.os_path.join(
5222 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5223 from helper import git_helper
5224 from helper import translation_helper
5225 finally:
5226 sys.path = old_sys_path
5227
5228 # Check that translation expectations can be parsed and we can get a list of
5229 # translatable grd files. |repo_root| and |translation_expectations_path| are
5230 # only passed by tests.
5231 if not repo_root:
5232 repo_root = input_api.PresubmitLocalPath()
5233 if not translation_expectations_path:
5234 translation_expectations_path = input_api.os_path.join(
5235 repo_root, 'tools', 'gritsettings',
5236 'translation_expectations.pyl')
5237 if not grd_files:
5238 grd_files = git_helper.list_grds_in_repository(repo_root)
5239
5240 try:
5241 translation_helper.get_translatable_grds(repo_root, grd_files,
5242 translation_expectations_path)
5243 except Exception as e:
5244 return [output_api.PresubmitNotifyResult(
5245 'Failed to get a list of translatable grd files. This happens when:\n'
5246 ' - One of the modified grd or grdp files cannot be parsed or\n'
5247 ' - %s is not updated.\n'
5248 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5249 return []
Ken Rockotc31f4832020-05-29 18:58:515250
5251
5252def _CheckStableMojomChanges(input_api, output_api):
5253 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095254 changed_mojoms = input_api.AffectedFiles(
5255 include_deletes=True,
5256 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515257 delta = []
5258 for mojom in changed_mojoms:
5259 old_contents = ''.join(mojom.OldContents()) or None
5260 new_contents = ''.join(mojom.NewContents()) or None
5261 delta.append({
5262 'filename': mojom.LocalPath(),
5263 'old': '\n'.join(mojom.OldContents()) or None,
5264 'new': '\n'.join(mojom.NewContents()) or None,
5265 })
5266
5267 process = input_api.subprocess.Popen(
5268 [input_api.python_executable,
5269 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5270 'public', 'tools', 'mojom',
5271 'check_stable_mojom_compatibility.py'),
5272 '--src-root', input_api.PresubmitLocalPath()],
5273 stdin=input_api.subprocess.PIPE,
5274 stdout=input_api.subprocess.PIPE,
5275 stderr=input_api.subprocess.PIPE,
5276 universal_newlines=True)
5277 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5278 if process.returncode:
5279 return [output_api.PresubmitError(
5280 'One or more [Stable] mojom definitions appears to have been changed '
5281 'in a way that is not backward-compatible.',
5282 long_text=error)]
5283 return []