blob: ec49d8cc57c2656e50451e9c0baaaaa1211a5751 [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/',
danakj7a2b7082019-05-21 21:13:51389 '^net/',
390 '^ppapi/proxy/',
391 '^ppapi/shared_impl/',
392 '^ppapi/tests/',
393 '^ppapi/thunk/',
danakj7a2b7082019-05-21 21:13:51394 '^remoting/host/',
395 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51396 '^services/',
danakj7a2b7082019-05-21 21:13:51397 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51398 '^tools/clang/base_bind_rewriters/', # Intentional.
399 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51400))
[email protected]127f18ec2012-06-16 05:05:59401
Daniel Bratell609102be2019-03-27 20:53:21402# Format: Sequence of tuples containing:
403# * String pattern or, if starting with a slash, a regular expression.
404# * Sequence of strings to show when the pattern matches.
405# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
406# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59407_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20408 (
Dave Tapuska98199b612019-07-10 13:30:44409 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53410 (
411 'New code should not use NULL. Use nullptr instead.',
412 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20413 False,
thomasandersone7caaa9b2017-03-29 19:22:53414 (),
415 ),
Peter Kasting94a56c42019-10-25 21:54:04416 (
417 r'/\busing namespace ',
418 (
419 'Using directives ("using namespace x") are banned by the Google Style',
420 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
421 'Explicitly qualify symbols or use using declarations ("using x::foo").',
422 ),
423 True,
424 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
425 ),
Antonio Gomes07300d02019-03-13 20:59:57426 # Make sure that gtest's FRIEND_TEST() macro is not used; the
427 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
428 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53429 (
[email protected]23e6cbc2012-06-16 18:51:20430 'FRIEND_TEST(',
431 (
[email protected]e3c945502012-06-26 20:01:49432 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20433 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
434 ),
435 False,
[email protected]7345da02012-11-27 14:31:49436 (),
[email protected]23e6cbc2012-06-16 18:51:20437 ),
438 (
Dave Tapuska98199b612019-07-10 13:30:44439 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53440 (
441 'Chrome clients wishing to select events on X windows should use',
442 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
443 'you are selecting events from the GPU process, or if you are using',
444 'an XDisplay other than gfx::GetXDisplay().',
445 ),
446 True,
447 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40448 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04449 r"^ui[\\/]gl[\\/].*\.cc$",
450 r"^media[\\/]gpu[\\/].*\.cc$",
451 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37452 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
453 ),
thomasanderson4b569052016-09-14 20:15:53454 ),
455 (
Dave Tapuska98199b612019-07-10 13:30:44456 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20457 (
thomasanderson11aa41dc2017-06-08 22:22:38458 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20459 ),
460 True,
461 (
Egor Paskoce145c42018-09-28 19:31:04462 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
463 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
464 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20465 ),
466 ),
467 (
tomhudsone2c14d552016-05-26 17:07:46468 'setMatrixClip',
469 (
470 'Overriding setMatrixClip() is prohibited; ',
471 'the base function is deprecated. ',
472 ),
473 True,
474 (),
475 ),
476 (
[email protected]52657f62013-05-20 05:30:31477 'SkRefPtr',
478 (
479 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22480 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31481 ),
482 True,
483 (),
484 ),
485 (
486 'SkAutoRef',
487 (
488 'The indirect use of SkRefPtr via SkAutoRef 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 'SkAutoTUnref',
496 (
497 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22498 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
503 (
504 'SkAutoUnref',
505 (
506 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
507 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22508 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31509 ),
510 True,
511 (),
512 ),
[email protected]d89eec82013-12-03 14:10:59513 (
514 r'/HANDLE_EINTR\(.*close',
515 (
516 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
517 'descriptor will be closed, and it is incorrect to retry the close.',
518 'Either call close directly and ignore its return value, or wrap close',
519 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
520 ),
521 True,
522 (),
523 ),
524 (
525 r'/IGNORE_EINTR\((?!.*close)',
526 (
527 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
528 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
529 ),
530 True,
531 (
532 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04533 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
534 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59535 ),
536 ),
[email protected]ec5b3f02014-04-04 18:43:43537 (
538 r'/v8::Extension\(',
539 (
540 'Do not introduce new v8::Extensions into the code base, use',
541 'gin::Wrappable instead. See http://crbug.com/334679',
542 ),
543 True,
[email protected]f55c90ee62014-04-12 00:50:03544 (
Egor Paskoce145c42018-09-28 19:31:04545 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03546 ),
[email protected]ec5b3f02014-04-04 18:43:43547 ),
skyostilf9469f72015-04-20 10:38:52548 (
jame2d1a952016-04-02 00:27:10549 '#pragma comment(lib,',
550 (
551 'Specify libraries to link with in build files and not in the source.',
552 ),
553 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41554 (
tzik3f295992018-12-04 20:32:23555 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04556 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41557 ),
jame2d1a952016-04-02 00:27:10558 ),
fdorayc4ac18d2017-05-01 21:39:59559 (
Gabriel Charette7cc6c432018-04-25 20:52:02560 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59561 (
562 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
563 ),
564 False,
565 (),
566 ),
567 (
Gabriel Charette7cc6c432018-04-25 20:52:02568 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59569 (
570 'Consider using THREAD_CHECKER macros instead of the class directly.',
571 ),
572 False,
573 (),
574 ),
dbeamb6f4fde2017-06-15 04:03:06575 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06576 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
577 (
578 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
579 'deprecated (http://crbug.com/634507). Please avoid converting away',
580 'from the Time types in Chromium code, especially if any math is',
581 'being done on time values. For interfacing with platform/library',
582 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
583 'type converter methods instead. For faking TimeXXX values (for unit',
584 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
585 'other use cases, please contact base/time/OWNERS.',
586 ),
587 False,
588 (),
589 ),
590 (
dbeamb6f4fde2017-06-15 04:03:06591 'CallJavascriptFunctionUnsafe',
592 (
593 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
594 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
595 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
596 ),
597 False,
598 (
Egor Paskoce145c42018-09-28 19:31:04599 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
600 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
601 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06602 ),
603 ),
dskiba1474c2bfd62017-07-20 02:19:24604 (
605 'leveldb::DB::Open',
606 (
607 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
608 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
609 "Chrome's tracing, making their memory usage visible.",
610 ),
611 True,
612 (
613 r'^third_party/leveldatabase/.*\.(cc|h)$',
614 ),
Gabriel Charette0592c3a2017-07-26 12:02:04615 ),
616 (
Chris Mumfordc38afb62017-10-09 17:55:08617 'leveldb::NewMemEnv',
618 (
619 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58620 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
621 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08622 ),
623 True,
624 (
625 r'^third_party/leveldatabase/.*\.(cc|h)$',
626 ),
627 ),
628 (
Gabriel Charetted9839bc2017-07-29 14:17:47629 'RunLoop::QuitCurrent',
630 (
Robert Liao64b7ab22017-08-04 23:03:43631 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
632 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47633 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41634 False,
Gabriel Charetted9839bc2017-07-29 14:17:47635 (),
Gabriel Charettea44975052017-08-21 23:14:04636 ),
637 (
638 'base::ScopedMockTimeMessageLoopTaskRunner',
639 (
Gabriel Charette87cc1af2018-04-25 20:52:51640 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11641 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51642 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
643 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
644 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04645 ),
Gabriel Charette87cc1af2018-04-25 20:52:51646 False,
Gabriel Charettea44975052017-08-21 23:14:04647 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57648 ),
649 (
Dave Tapuska98199b612019-07-10 13:30:44650 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57651 (
652 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02653 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57654 ),
655 True,
656 (),
Francois Doray43670e32017-09-27 12:40:38657 ),
658 (
Peter Kasting991618a62019-06-17 22:00:09659 r'/\bstd::stoi\b',
660 (
661 'std::stoi uses exceptions to communicate results. ',
662 'Use base::StringToInt() instead.',
663 ),
664 True,
665 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
666 ),
667 (
668 r'/\bstd::stol\b',
669 (
670 'std::stol 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::stoul\b',
678 (
679 'std::stoul uses exceptions to communicate results. ',
680 'Use base::StringToUint() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stoll\b',
687 (
688 'std::stoll uses exceptions to communicate results. ',
689 'Use base::StringToInt64() instead.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
695 r'/\bstd::stoull\b',
696 (
697 'std::stoull uses exceptions to communicate results. ',
698 'Use base::StringToUint64() instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
702 ),
703 (
704 r'/\bstd::stof\b',
705 (
706 'std::stof uses exceptions to communicate results. ',
707 'For locale-independent values, e.g. reading numbers from disk',
708 'profiles, use base::StringToDouble().',
709 'For user-visible values, parse using ICU.',
710 ),
711 True,
712 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
713 ),
714 (
715 r'/\bstd::stod\b',
716 (
717 'std::stod uses exceptions to communicate results. ',
718 'For locale-independent values, e.g. reading numbers from disk',
719 'profiles, use base::StringToDouble().',
720 'For user-visible values, parse using ICU.',
721 ),
722 True,
723 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
724 ),
725 (
726 r'/\bstd::stold\b',
727 (
728 'std::stold uses exceptions to communicate results. ',
729 'For locale-independent values, e.g. reading numbers from disk',
730 'profiles, use base::StringToDouble().',
731 'For user-visible values, parse using ICU.',
732 ),
733 True,
734 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
735 ),
736 (
Daniel Bratell69334cc2019-03-26 11:07:45737 r'/\bstd::to_string\b',
738 (
739 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09740 'For locale-independent strings, e.g. writing numbers to disk',
741 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45742 'For user-visible strings, use base::FormatNumber() and',
743 'the related functions in base/i18n/number_formatting.h.',
744 ),
Peter Kasting991618a62019-06-17 22:00:09745 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21746 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45747 ),
748 (
749 r'/\bstd::shared_ptr\b',
750 (
751 'std::shared_ptr should not be used. Use scoped_refptr instead.',
752 ),
753 True,
Andreas Haas63f58792019-11-07 10:56:44754 [_THIRD_PARTY_EXCEPT_BLINK,
755 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
756 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21757 ),
758 (
Peter Kasting991618a62019-06-17 22:00:09759 r'/\bstd::weak_ptr\b',
760 (
761 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
762 ),
763 True,
764 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
765 ),
766 (
Daniel Bratell609102be2019-03-27 20:53:21767 r'/\blong long\b',
768 (
769 'long long is banned. Use stdint.h if you need a 64 bit number.',
770 ),
771 False, # Only a warning since it is already used.
772 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
773 ),
774 (
775 r'/\bstd::bind\b',
776 (
777 'std::bind is banned because of lifetime risks.',
778 'Use base::BindOnce or base::BindRepeating instead.',
779 ),
780 True,
781 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
782 ),
783 (
784 r'/\b#include <chrono>\b',
785 (
786 '<chrono> overlaps with Time APIs in base. Keep using',
787 'base classes.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\b#include <exception>\b',
794 (
795 'Exceptions are banned and disabled in Chromium.',
796 ),
797 True,
798 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
799 ),
800 (
801 r'/\bstd::function\b',
802 (
803 'std::function is banned. Instead use base::Callback which directly',
804 'supports Chromium\'s weak pointers, ref counting and more.',
805 ),
Peter Kasting991618a62019-06-17 22:00:09806 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21807 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
808 ),
809 (
810 r'/\b#include <random>\b',
811 (
812 'Do not use any random number engines from <random>. Instead',
813 'use base::RandomBitGenerator.',
814 ),
815 True,
816 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
817 ),
818 (
819 r'/\bstd::ratio\b',
820 (
821 'std::ratio is banned by the Google Style Guide.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45825 ),
826 (
Francois Doray43670e32017-09-27 12:40:38827 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
828 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
829 (
830 'Use the new API in base/threading/thread_restrictions.h.',
831 ),
Gabriel Charette04b138f2018-08-06 00:03:22832 False,
Francois Doray43670e32017-09-27 12:40:38833 (),
834 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38835 (
danakj7a2b7082019-05-21 21:13:51836 r'/\bbase::Bind\(',
837 (
838 'Please use base::Bind{Once,Repeating} instead',
839 'of base::Bind. (crbug.com/714018)',
840 ),
841 False,
Erik Staaba737d7602019-11-25 18:41:07842 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51843 ),
844 (
845 r'/\bbase::Callback[<:]',
846 (
847 'Please use base::{Once,Repeating}Callback instead',
848 'of base::Callback. (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::Closure\b',
855 (
856 'Please use base::{Once,Repeating}Closure instead',
857 'of base::Closure. (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 (
Michael Giuffrida7f93d6922019-04-19 14:39:58863 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19864 (
865 'RunMessageLoop is deprecated, use RunLoop instead.',
866 ),
867 False,
868 (),
869 ),
870 (
Dave Tapuska98199b612019-07-10 13:30:44871 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
874 ),
875 False,
876 (),
877 ),
878 (
Dave Tapuska98199b612019-07-10 13:30:44879 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19880 (
881 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
882 "if you're convinced you need this.",
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04891 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19892 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
893 'async events instead of flushing threads.',
894 ),
895 False,
896 (),
897 ),
898 (
899 r'MessageLoopRunner',
900 (
901 'MessageLoopRunner is deprecated, use RunLoop instead.',
902 ),
903 False,
904 (),
905 ),
906 (
Dave Tapuska98199b612019-07-10 13:30:44907 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19908 (
909 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
910 "gab@ if you found a use case where this is the only solution.",
911 ),
912 False,
913 (),
914 ),
915 (
Victor Costane48a2e82019-03-15 22:02:34916 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16917 (
Victor Costane48a2e82019-03-15 22:02:34918 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16919 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
920 ),
921 True,
922 (
923 r'^sql/initialization\.(cc|h)$',
924 r'^third_party/sqlite/.*\.(c|cc|h)$',
925 ),
926 ),
Matt Menke7f520a82018-03-28 21:38:37927 (
Dave Tapuska98199b612019-07-10 13:30:44928 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47929 (
930 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
931 'base::RandomShuffle instead.'
932 ),
933 True,
934 (),
935 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24936 (
937 'ios/web/public/test/http_server',
938 (
939 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
940 ),
941 False,
942 (),
943 ),
Robert Liao764c9492019-01-24 18:46:28944 (
945 'GetAddressOf',
946 (
947 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53948 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
949 'operator& is generally recommended. So always use operator& instead. '
950 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28951 ),
952 True,
953 (),
954 ),
Antonio Gomes07300d02019-03-13 20:59:57955 (
956 'DEFINE_TYPE_CASTS',
957 (
958 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
959 '//third_party/blink/renderer/platform/casting.h.'
960 ),
961 True,
962 (
963 r'^third_party/blink/renderer/.*\.(cc|h)$',
964 ),
965 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38966 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45967 r'/\bIsHTML.+Element\(\b',
968 (
969 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
970 ' helpers IsA<HTMLXXXXElement> from ',
971 '//third_party/blink/renderer/platform/casting.h.'
972 ),
973 False,
974 (
975 r'^third_party/blink/renderer/.*\.(cc|h)$',
976 ),
977 ),
978 (
979 r'/\bToHTML.+Element(|OrNull)\(\b',
980 (
981 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
982 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
983 'and DynamicTo<HTMLXXXXElement> from ',
984 '//third_party/blink/renderer/platform/casting.h.'
985 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
986 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
987 ),
988 False,
989 (
990 r'^third_party/blink/renderer/.*\.(cc|h)$',
991 ),
992 ),
993 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37994 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38995 (
996 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
997 ),
998 True,
999 (),
1000 ),
Ben Lewisa9514602019-04-29 17:53:051001 (
1002 'SHFileOperation',
1003 (
1004 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1005 'complex functions to achieve the same goals. Use IFileOperation for ',
1006 'any esoteric actions instead.'
1007 ),
1008 True,
1009 (),
1010 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181011 (
Cliff Smolinsky81951642019-04-30 21:39:511012 'StringFromGUID2',
1013 (
1014 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1015 'Use base::win::String16FromGUID instead.'
1016 ),
1017 True,
1018 (
1019 r'/base/win/win_util_unittest.cc'
1020 ),
1021 ),
1022 (
1023 'StringFromCLSID',
1024 (
1025 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1026 'Use base::win::String16FromGUID instead.'
1027 ),
1028 True,
1029 (
1030 r'/base/win/win_util_unittest.cc'
1031 ),
1032 ),
1033 (
Avi Drissman7382afa02019-04-29 23:27:131034 'kCFAllocatorNull',
1035 (
1036 'The use of kCFAllocatorNull with the NoCopy creation of ',
1037 'CoreFoundation types is prohibited.',
1038 ),
1039 True,
1040 (),
1041 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291042 (
1043 'mojo::ConvertTo',
1044 (
1045 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1046 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1047 'StringTraits if you would like to convert between custom types and',
1048 'the wire format of mojom types.'
1049 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221050 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291051 (
Wezf89dec092019-09-11 19:38:331052 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1053 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291054 r'^third_party/blink/.*\.(cc|h)$',
1055 r'^content/renderer/.*\.(cc|h)$',
1056 ),
1057 ),
Robert Liao1d78df52019-11-11 20:02:011058 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161059 'GetInterfaceProvider',
1060 (
1061 'InterfaceProvider is deprecated.',
1062 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1063 'or Platform::GetBrowserInterfaceBroker.'
1064 ),
1065 False,
1066 (),
1067 ),
1068 (
Robert Liao1d78df52019-11-11 20:02:011069 'CComPtr',
1070 (
1071 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1072 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1073 'details.'
1074 ),
1075 False,
1076 (),
1077 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201078 (
1079 r'/\b(IFACE|STD)METHOD_?\(',
1080 (
1081 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1082 'Instead, always use IFACEMETHODIMP in the declaration.'
1083 ),
1084 False,
1085 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1086 ),
Allen Bauer53b43fb12020-03-12 17:21:471087 (
1088 'set_owned_by_client',
1089 (
1090 'set_owned_by_client is deprecated.',
1091 'views::View already owns the child views by default. This introduces ',
1092 'a competing ownership model which makes the code difficult to reason ',
1093 'about. See http://crbug.com/1044687 for more details.'
1094 ),
1095 False,
1096 (),
1097 ),
Eric Secklerbe6f48d2020-05-06 18:09:121098 (
1099 r'/\bTRACE_EVENT_ASYNC_',
1100 (
1101 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1102 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1103 ),
1104 False,
1105 (
1106 r'^base/trace_event/.*',
1107 r'^base/tracing/.*',
1108 ),
1109 ),
[email protected]127f18ec2012-06-16 05:05:591110)
1111
Mario Sanchez Prada2472cab2019-09-18 10:58:311112# Format: Sequence of tuples containing:
1113# * String pattern or, if starting with a slash, a regular expression.
1114# * Sequence of strings to show when the pattern matches.
1115_DEPRECATED_MOJO_TYPES = (
1116 (
1117 r'/\bmojo::AssociatedBinding\b',
1118 (
1119 'mojo::AssociatedBinding<Interface> is deprecated.',
1120 'Use mojo::AssociatedReceiver<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedBindingSet\b',
1125 (
1126 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1127 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::AssociatedInterfacePtr\b',
1132 (
1133 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1134 'Use mojo::AssociatedRemote<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1139 (
1140 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1141 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::AssociatedInterfaceRequest\b',
1146 (
1147 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1148 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::Binding\b',
1153 (
1154 'mojo::Binding<Interface> is deprecated.',
1155 'Use mojo::Receiver<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::BindingSet\b',
1160 (
1161 'mojo::BindingSet<Interface> is deprecated.',
1162 'Use mojo::ReceiverSet<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::InterfacePtr\b',
1167 (
1168 'mojo::InterfacePtr<Interface> is deprecated.',
1169 'Use mojo::Remote<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::InterfacePtrInfo\b',
1174 (
1175 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1176 'Use mojo::PendingRemote<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::InterfaceRequest\b',
1181 (
1182 'mojo::InterfaceRequest<Interface> is deprecated.',
1183 'Use mojo::PendingReceiver<Interface> instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::MakeRequest\b',
1188 (
1189 'mojo::MakeRequest is deprecated.',
1190 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1191 ),
1192 ),
1193 (
1194 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1195 (
1196 'mojo::MakeRequest is deprecated.',
1197 'Use mojo::AssociatedRemote::'
1198 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeStrongBinding\b',
1203 (
1204 'mojo::MakeStrongBinding is deprecated.',
1205 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1206 'mojo::MakeSelfOwnedReceiver() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongAssociatedBinding\b',
1211 (
1212 'mojo::MakeStrongAssociatedBinding is deprecated.',
1213 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1214 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1215 ),
1216 ),
1217 (
Gyuyoung Kim4952ba62020-07-07 07:33:441218 r'/\bmojo::StrongAssociatedBinding\b',
1219 (
1220 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1221 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1222 ),
1223 ),
1224 (
1225 r'/\bmojo::StrongBinding\b',
1226 (
1227 'mojo::StrongBinding<Interface> is deprecated.',
1228 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1229 ),
1230 ),
1231 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311232 r'/\bmojo::StrongAssociatedBindingSet\b',
1233 (
1234 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1235 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1236 ),
1237 ),
1238 (
1239 r'/\bmojo::StrongBindingSet\b',
1240 (
1241 'mojo::StrongBindingSet<Interface> is deprecated.',
1242 'Use mojo::UniqueReceiverSet<Interface> instead.',
1243 ),
1244 ),
1245)
wnwenbdc444e2016-05-25 13:44:151246
mlamouria82272622014-09-16 18:45:041247_IPC_ENUM_TRAITS_DEPRECATED = (
1248 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501249 'See http://www.chromium.org/Home/chromium-security/education/'
1250 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041251
Stephen Martinis97a394142018-06-07 23:06:051252_LONG_PATH_ERROR = (
1253 'Some files included in this CL have file names that are too long (> 200'
1254 ' characters). If committed, these files will cause issues on Windows. See'
1255 ' https://crbug.com/612667 for more details.'
1256)
1257
Shenghua Zhangbfaa38b82017-11-16 21:58:021258_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041259 r".*[\\/]BuildHooksAndroidImpl\.java",
1260 r".*[\\/]LicenseContentProvider\.java",
1261 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281262 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021263]
[email protected]127f18ec2012-06-16 05:05:591264
Mohamed Heikald048240a2019-11-12 16:57:371265# List of image extensions that are used as resources in chromium.
1266_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1267
Sean Kau46e29bc2017-08-28 16:31:161268# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401269_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041270 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401271 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041272 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1273 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041274 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431275 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161276]
1277
1278
[email protected]b00342e7f2013-03-26 16:21:541279_VALID_OS_MACROS = (
1280 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081281 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121283 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_BSD',
1285 'OS_CAT', # For testing.
1286 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041287 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541288 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371289 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541290 'OS_IOS',
1291 'OS_LINUX',
1292 'OS_MACOSX',
1293 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211294 'OS_NACL_NONSFI',
1295 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121296 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541297 'OS_OPENBSD',
1298 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371299 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541300 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541301 'OS_WIN',
1302)
1303
1304
Andrew Grieveb773bad2020-06-05 18:00:381305# These are not checked on the public chromium-presubmit trybot.
1306# Add files here that rely on .py files that exists only for target_os="android"
1307# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401308_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391309 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381310 'build/android/devil_chromium.pydeps',
1311 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1312 'build/android/gyp/jinja_template.pydeps',
1313 'build/android/resource_sizes.pydeps',
1314 'build/android/test_runner.pydeps',
1315 'build/android/test_wrapper/logdog_wrapper.pydeps',
1316 'chrome/android/features/create_stripped_java_factory.pydeps',
1317 'testing/scripts/run_android_wpt.pydeps',
1318 'third_party/android_platform/development/scripts/stack.pydeps',
1319]
1320
1321
1322_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'base/android/jni_generator/jni_generator.pydeps',
1324 'base/android/jni_generator/jni_registration_generator.pydeps',
1325 'build/android/gyp/aar.pydeps',
1326 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271327 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381329 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111331 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111335 'build/android/gyp/create_app_bundle_apks.pydeps',
1336 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221338 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001339 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591341 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421343 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361345 'build/android/gyp/filter_zip.pydeps',
1346 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361347 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581349 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261351 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011352 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/lint.pydeps',
1354 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/android/gyp/merge_manifest.pydeps',
1356 'build/android/gyp/prepare_resources.pydeps',
1357 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461358 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241359 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461361 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561362 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361363 'build/android/incremental_install/generate_android_manifest.pydeps',
1364 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361365 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271366 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1367 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001368 'components/cronet/tools/generate_javadoc.pydeps',
1369 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381370 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001371 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381372 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421373 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1374 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131375 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191376 ('third_party/blink/renderer/bindings/scripts/'
1377 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061378 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221379 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401380]
1381
wnwenbdc444e2016-05-25 13:44:151382
agrievef32bcc72016-04-04 14:57:401383_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1384
1385
Eric Boren6fd2b932018-01-25 15:05:081386# Bypass the AUTHORS check for these accounts.
1387_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591388 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451389 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591390 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521391 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1392 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041393 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271394 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041395 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301396 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081397
1398
Daniel Bratell65b033262019-04-23 08:17:061399def _IsCPlusPlusFile(input_api, file_path):
1400 """Returns True if this file contains C++-like code (and not Python,
1401 Go, Java, MarkDown, ...)"""
1402
1403 ext = input_api.os_path.splitext(file_path)[1]
1404 # This list is compatible with CppChecker.IsCppFile but we should
1405 # consider adding ".c" to it. If we do that we can use this function
1406 # at more places in the code.
1407 return ext in (
1408 '.h',
1409 '.cc',
1410 '.cpp',
1411 '.m',
1412 '.mm',
1413 )
1414
1415def _IsCPlusPlusHeaderFile(input_api, file_path):
1416 return input_api.os_path.splitext(file_path)[1] == ".h"
1417
1418
1419def _IsJavaFile(input_api, file_path):
1420 return input_api.os_path.splitext(file_path)[1] == ".java"
1421
1422
1423def _IsProtoFile(input_api, file_path):
1424 return input_api.os_path.splitext(file_path)[1] == ".proto"
1425
[email protected]55459852011-08-10 15:17:191426def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1427 """Attempts to prevent use of functions intended only for testing in
1428 non-testing code. For now this is just a best-effort implementation
1429 that ignores header files and may have some false positives. A
1430 better implementation would probably need a proper C++ parser.
1431 """
1432 # We only scan .cc files and the like, as the declaration of
1433 # for-testing functions in header files are hard to distinguish from
1434 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491435 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191436
jochenc0d4808c2015-07-27 09:25:421437 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191438 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091439 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191440 exclusion_pattern = input_api.re.compile(
1441 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1442 base_function_pattern, base_function_pattern))
1443
1444 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441445 black_list = (_EXCLUDED_PATHS +
1446 _TEST_CODE_EXCLUDED_PATHS +
1447 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191448 return input_api.FilterSourceFile(
1449 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491450 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191451 black_list=black_list)
1452
1453 problems = []
1454 for f in input_api.AffectedSourceFiles(FilterFile):
1455 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241456 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031457 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461458 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031459 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191460 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031461 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191462
1463 if problems:
[email protected]f7051d52013-04-02 18:31:421464 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031465 else:
1466 return []
[email protected]55459852011-08-10 15:17:191467
1468
Vaclav Brozek7dbc28c2018-03-27 08:35:231469def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1470 """This is a simplified version of
1471 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1472 """
1473 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1474 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1475 name_pattern = r'ForTest(s|ing)?'
1476 # Describes an occurrence of "ForTest*" inside a // comment.
1477 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1478 # Catch calls.
1479 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1480 # Ignore definitions. (Comments are ignored separately.)
1481 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1482
1483 problems = []
1484 sources = lambda x: input_api.FilterSourceFile(
1485 x,
1486 black_list=(('(?i).*test', r'.*\/junit\/')
1487 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491488 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231489 )
1490 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1491 local_path = f.LocalPath()
1492 is_inside_javadoc = False
1493 for line_number, line in f.ChangedContents():
1494 if is_inside_javadoc and javadoc_end_re.search(line):
1495 is_inside_javadoc = False
1496 if not is_inside_javadoc and javadoc_start_re.search(line):
1497 is_inside_javadoc = True
1498 if is_inside_javadoc:
1499 continue
1500 if (inclusion_re.search(line) and
1501 not comment_re.search(line) and
1502 not exclusion_re.search(line)):
1503 problems.append(
1504 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1505
1506 if problems:
1507 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1508 else:
1509 return []
1510
1511
[email protected]10689ca2011-09-02 02:31:541512def _CheckNoIOStreamInHeaders(input_api, output_api):
1513 """Checks to make sure no .h files include <iostream>."""
1514 files = []
1515 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1516 input_api.re.MULTILINE)
1517 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1518 if not f.LocalPath().endswith('.h'):
1519 continue
1520 contents = input_api.ReadFile(f)
1521 if pattern.search(contents):
1522 files.append(f)
1523
1524 if len(files):
yolandyandaabc6d2016-04-18 18:29:391525 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061526 'Do not #include <iostream> in header files, since it inserts static '
1527 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541528 '#include <ostream>. See http://crbug.com/94794',
1529 files) ]
1530 return []
1531
Danil Chapovalov3518f362018-08-11 16:13:431532def _CheckNoStrCatRedefines(input_api, output_api):
1533 """Checks no windows headers with StrCat redefined are included directly."""
1534 files = []
1535 pattern_deny = input_api.re.compile(
1536 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1537 input_api.re.MULTILINE)
1538 pattern_allow = input_api.re.compile(
1539 r'^#include\s"base/win/windows_defines.inc"',
1540 input_api.re.MULTILINE)
1541 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1542 contents = input_api.ReadFile(f)
1543 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1544 files.append(f.LocalPath())
1545
1546 if len(files):
1547 return [output_api.PresubmitError(
1548 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1549 'directly since they pollute code with StrCat macro. Instead, '
1550 'include matching header from base/win. See http://crbug.com/856536',
1551 files) ]
1552 return []
1553
[email protected]10689ca2011-09-02 02:31:541554
[email protected]72df4e782012-06-21 16:28:181555def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521556 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181557 problems = []
1558 for f in input_api.AffectedFiles():
1559 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1560 continue
1561
1562 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041563 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181564 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1565
1566 if not problems:
1567 return []
1568 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1569 '\n'.join(problems))]
1570
Dominic Battre033531052018-09-24 15:45:341571def _CheckNoDISABLETypoInTests(input_api, output_api):
1572 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1573
1574 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1575 instead of DISABLED_. To filter false positives, reports are only generated
1576 if a corresponding MAYBE_ line exists.
1577 """
1578 problems = []
1579
1580 # The following two patterns are looked for in tandem - is a test labeled
1581 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1582 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1583 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1584
1585 # This is for the case that a test is disabled on all platforms.
1586 full_disable_pattern = input_api.re.compile(
1587 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1588 input_api.re.MULTILINE)
1589
Katie Df13948e2018-09-25 07:33:441590 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341591 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1592 continue
1593
1594 # Search for MABYE_, DISABLE_ pairs.
1595 disable_lines = {} # Maps of test name to line number.
1596 maybe_lines = {}
1597 for line_num, line in f.ChangedContents():
1598 disable_match = disable_pattern.search(line)
1599 if disable_match:
1600 disable_lines[disable_match.group(1)] = line_num
1601 maybe_match = maybe_pattern.search(line)
1602 if maybe_match:
1603 maybe_lines[maybe_match.group(1)] = line_num
1604
1605 # Search for DISABLE_ occurrences within a TEST() macro.
1606 disable_tests = set(disable_lines.keys())
1607 maybe_tests = set(maybe_lines.keys())
1608 for test in disable_tests.intersection(maybe_tests):
1609 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1610
1611 contents = input_api.ReadFile(f)
1612 full_disable_match = full_disable_pattern.search(contents)
1613 if full_disable_match:
1614 problems.append(' %s' % f.LocalPath())
1615
1616 if not problems:
1617 return []
1618 return [
1619 output_api.PresubmitPromptWarning(
1620 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1621 '\n'.join(problems))
1622 ]
1623
[email protected]72df4e782012-06-21 16:28:181624
danakj61c1aa22015-10-26 19:55:521625def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571626 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521627 errors = []
Hans Wennborg944479f2020-06-25 21:39:251628 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521629 input_api.re.MULTILINE)
1630 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1631 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1632 continue
1633 for lnum, line in f.ChangedContents():
1634 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171635 errors.append(output_api.PresubmitError(
1636 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571637 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171638 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521639 return errors
1640
1641
Makoto Shimazu3ad422cd2019-05-08 02:35:141642def _FindHistogramNameInChunk(histogram_name, chunk):
1643 """Tries to find a histogram name or prefix in a line.
1644
1645 Returns the existence of the histogram name, or None if it needs more chunk
1646 to determine."""
mcasasb7440c282015-02-04 14:52:191647 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1648 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141649 if '<affected-histogram' in chunk:
1650 # If the tag is not completed, needs more chunk to get the name.
1651 if not '>' in chunk:
1652 return None
1653 if not 'name="' in chunk:
1654 return False
1655 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1656 # expect the only attribute is the name.
1657 histogram_prefix = chunk.split('"')[1]
1658 return histogram_prefix in histogram_name
1659 # Typically the whole histogram name should in the line.
1660 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191661
1662
1663def _CheckUmaHistogramChanges(input_api, output_api):
1664 """Check that UMA histogram names in touched lines can still be found in other
1665 lines of the patch or in histograms.xml. Note that this check would not catch
1666 the reverse: changes in histograms.xml not matched in the code itself."""
1667 touched_histograms = []
1668 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471669 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1670 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1671 name_pattern = r'"(.*?)"'
1672 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1673 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1674 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1675 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1676 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171677 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191678 for f in input_api.AffectedFiles():
1679 # If histograms.xml itself is modified, keep the modified lines for later.
1680 if f.LocalPath().endswith(('histograms.xml')):
1681 histograms_xml_modifications = f.ChangedContents()
1682 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471683 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1684 single_line_re = single_line_c_re
1685 split_line_prefix_re = split_line_c_prefix_re
1686 elif f.LocalPath().endswith(('java')):
1687 single_line_re = single_line_java_re
1688 split_line_prefix_re = split_line_java_prefix_re
1689 else:
mcasasb7440c282015-02-04 14:52:191690 continue
1691 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171692 if last_line_matched_prefix:
1693 suffix_found = split_line_suffix_re.search(line)
1694 if suffix_found :
1695 touched_histograms.append([suffix_found.group(1), f, line_num])
1696 last_line_matched_prefix = False
1697 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061698 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191699 if found:
1700 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171701 continue
1702 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191703
1704 # Search for the touched histogram names in the local modifications to
1705 # histograms.xml, and, if not found, on the base histograms.xml file.
1706 unmatched_histograms = []
1707 for histogram_info in touched_histograms:
1708 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141709 chunk = ''
mcasasb7440c282015-02-04 14:52:191710 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141711 chunk += line
1712 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1713 if histogram_name_found is None:
1714 continue
1715 chunk = ''
mcasasb7440c282015-02-04 14:52:191716 if histogram_name_found:
1717 break
1718 if not histogram_name_found:
1719 unmatched_histograms.append(histogram_info)
1720
eromanb90c82e7e32015-04-01 15:13:491721 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191722 problems = []
1723 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491724 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191725 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451726 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191727 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141728 chunk = ''
mcasasb7440c282015-02-04 14:52:191729 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141730 chunk += line
1731 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1732 chunk)
1733 if histogram_name_found is None:
1734 continue
1735 chunk = ''
mcasasb7440c282015-02-04 14:52:191736 if histogram_name_found:
1737 break
1738 if not histogram_name_found:
1739 problems.append(' [%s:%d] %s' %
1740 (f.LocalPath(), line_num, histogram_name))
1741
1742 if not problems:
1743 return []
1744 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1745 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491746 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191747
wnwenbdc444e2016-05-25 13:44:151748
yolandyandaabc6d2016-04-18 18:29:391749def _CheckFlakyTestUsage(input_api, output_api):
1750 """Check that FlakyTest annotation is our own instead of the android one"""
1751 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1752 files = []
1753 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1754 if f.LocalPath().endswith('Test.java'):
1755 if pattern.search(input_api.ReadFile(f)):
1756 files.append(f)
1757 if len(files):
1758 return [output_api.PresubmitError(
1759 'Use org.chromium.base.test.util.FlakyTest instead of '
1760 'android.test.FlakyTest',
1761 files)]
1762 return []
mcasasb7440c282015-02-04 14:52:191763
wnwenbdc444e2016-05-25 13:44:151764
[email protected]8ea5d4b2011-09-13 21:49:221765def _CheckNoNewWStrings(input_api, output_api):
1766 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271767 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221768 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201769 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571770 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341771 '/win/' in f.LocalPath() or
1772 'chrome_elf' in f.LocalPath() or
1773 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201774 continue
[email protected]8ea5d4b2011-09-13 21:49:221775
[email protected]a11dbe9b2012-08-07 01:32:581776 allowWString = False
[email protected]b5c24292011-11-28 14:38:201777 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581778 if 'presubmit: allow wstring' in line:
1779 allowWString = True
1780 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271781 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581782 allowWString = False
1783 else:
1784 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221785
[email protected]55463aa62011-10-12 00:48:271786 if not problems:
1787 return []
1788 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581789 ' If you are calling a cross-platform API that accepts a wstring, '
1790 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271791 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221792
1793
[email protected]2a8ac9c2011-10-19 17:20:441794def _CheckNoDEPSGIT(input_api, output_api):
1795 """Make sure .DEPS.git is never modified manually."""
1796 if any(f.LocalPath().endswith('.DEPS.git') for f in
1797 input_api.AffectedFiles()):
1798 return [output_api.PresubmitError(
1799 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1800 'automated system based on what\'s in DEPS and your changes will be\n'
1801 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501802 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1803 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441804 'for more information')]
1805 return []
1806
1807
tandriief664692014-09-23 14:51:471808def _CheckValidHostsInDEPS(input_api, output_api):
1809 """Checks that DEPS file deps are from allowed_hosts."""
1810 # Run only if DEPS file has been modified to annoy fewer bystanders.
1811 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1812 return []
1813 # Outsource work to gclient verify
1814 try:
John Budorickf20c0042019-04-25 23:23:401815 gclient_path = input_api.os_path.join(
1816 input_api.PresubmitLocalPath(),
1817 'third_party', 'depot_tools', 'gclient.py')
1818 input_api.subprocess.check_output(
1819 [input_api.python_executable, gclient_path, 'verify'],
1820 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471821 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201822 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471823 return [output_api.PresubmitError(
1824 'DEPS file must have only git dependencies.',
1825 long_text=error.output)]
1826
1827
Mario Sanchez Prada2472cab2019-09-18 10:58:311828def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1829 type_name, message):
1830 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1831
1832 Returns an string composed of the name of the file, the line number where the
1833 match has been found and the additional text passed as |message| in case the
1834 target type name matches the text inside the line passed as parameter.
1835 """
Peng Huang9c5949a02020-06-11 19:20:541836 result = []
1837
1838 if line.endswith(" nocheck"):
1839 return result
1840
Mario Sanchez Prada2472cab2019-09-18 10:58:311841 matched = False
1842 if type_name[0:1] == '/':
1843 regex = type_name[1:]
1844 if input_api.re.search(regex, line):
1845 matched = True
1846 elif type_name in line:
1847 matched = True
1848
Mario Sanchez Prada2472cab2019-09-18 10:58:311849 if matched:
1850 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1851 for message_line in message:
1852 result.append(' %s' % message_line)
1853
1854 return result
1855
1856
[email protected]127f18ec2012-06-16 05:05:591857def _CheckNoBannedFunctions(input_api, output_api):
1858 """Make sure that banned functions are not used."""
1859 warnings = []
1860 errors = []
1861
wnwenbdc444e2016-05-25 13:44:151862 def IsBlacklisted(affected_file, blacklist):
1863 local_path = affected_file.LocalPath()
1864 for item in blacklist:
1865 if input_api.re.match(item, local_path):
1866 return True
1867 return False
1868
Peter K. Lee6c03ccff2019-07-15 14:40:051869 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541870 local_path = affected_file.LocalPath()
1871 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1872 return False
1873 basename = input_api.os_path.basename(local_path)
1874 if 'ios' in basename.split('_'):
1875 return True
1876 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1877 if sep and 'ios' in local_path.split(sep):
1878 return True
1879 return False
1880
wnwenbdc444e2016-05-25 13:44:151881 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311882 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1883 func_name, message)
1884 if problems:
wnwenbdc444e2016-05-25 13:44:151885 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311886 errors.extend(problems)
1887 else:
1888 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151889
Eric Stevensona9a980972017-09-23 00:04:411890 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1891 for f in input_api.AffectedFiles(file_filter=file_filter):
1892 for line_num, line in f.ChangedContents():
1893 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1894 CheckForMatch(f, line_num, line, func_name, message, error)
1895
[email protected]127f18ec2012-06-16 05:05:591896 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1897 for f in input_api.AffectedFiles(file_filter=file_filter):
1898 for line_num, line in f.ChangedContents():
1899 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151900 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591901
Peter K. Lee6c03ccff2019-07-15 14:40:051902 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541903 for line_num, line in f.ChangedContents():
1904 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1905 CheckForMatch(f, line_num, line, func_name, message, error)
1906
Peter K. Lee6c03ccff2019-07-15 14:40:051907 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1908 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1909 for line_num, line in f.ChangedContents():
1910 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1911 CheckForMatch(f, line_num, line, func_name, message, error)
1912
[email protected]127f18ec2012-06-16 05:05:591913 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1914 for f in input_api.AffectedFiles(file_filter=file_filter):
1915 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491916 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491917 if IsBlacklisted(f, excluded_paths):
1918 continue
wnwenbdc444e2016-05-25 13:44:151919 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591920
1921 result = []
1922 if (warnings):
1923 result.append(output_api.PresubmitPromptWarning(
1924 'Banned functions were used.\n' + '\n'.join(warnings)))
1925 if (errors):
1926 result.append(output_api.PresubmitError(
1927 'Banned functions were used.\n' + '\n'.join(errors)))
1928 return result
1929
1930
Michael Thiessen44457642020-02-06 00:24:151931def _CheckAndroidNoBannedImports(input_api, output_api):
1932 """Make sure that banned java imports are not used."""
1933 errors = []
1934
1935 def IsException(path, exceptions):
1936 for exception in exceptions:
1937 if (path.startswith(exception)):
1938 return True
1939 return False
1940
1941 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1942 for f in input_api.AffectedFiles(file_filter=file_filter):
1943 for line_num, line in f.ChangedContents():
1944 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1945 if IsException(f.LocalPath(), exceptions):
1946 continue;
1947 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1948 'import ' + import_name, message)
1949 if problems:
1950 errors.extend(problems)
1951 result = []
1952 if (errors):
1953 result.append(output_api.PresubmitError(
1954 'Banned imports were used.\n' + '\n'.join(errors)))
1955 return result
1956
1957
Mario Sanchez Prada2472cab2019-09-18 10:58:311958def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1959 """Make sure that old Mojo types are not used."""
1960 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571961 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311962
Mario Sanchez Pradaaab91382019-12-19 08:57:091963 # For any path that is not an "ok" or an "error" path, a warning will be
1964 # raised if deprecated mojo types are found.
1965 ok_paths = ['components/arc']
1966 error_paths = ['third_party/blink', 'content']
1967
Mario Sanchez Prada2472cab2019-09-18 10:58:311968 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1969 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571970 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091971 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311972 continue
1973
1974 for line_num, line in f.ChangedContents():
1975 for func_name, message in _DEPRECATED_MOJO_TYPES:
1976 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1977 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571978
Mario Sanchez Prada2472cab2019-09-18 10:58:311979 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091980 # Raise errors inside |error_paths| and warnings everywhere else.
1981 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571982 errors.extend(problems)
1983 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311984 warnings.extend(problems)
1985
1986 result = []
1987 if (warnings):
1988 result.append(output_api.PresubmitPromptWarning(
1989 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571990 if (errors):
1991 result.append(output_api.PresubmitError(
1992 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311993 return result
1994
1995
[email protected]6c063c62012-07-11 19:11:061996def _CheckNoPragmaOnce(input_api, output_api):
1997 """Make sure that banned functions are not used."""
1998 files = []
1999 pattern = input_api.re.compile(r'^#pragma\s+once',
2000 input_api.re.MULTILINE)
2001 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2002 if not f.LocalPath().endswith('.h'):
2003 continue
2004 contents = input_api.ReadFile(f)
2005 if pattern.search(contents):
2006 files.append(f)
2007
2008 if files:
2009 return [output_api.PresubmitError(
2010 'Do not use #pragma once in header files.\n'
2011 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2012 files)]
2013 return []
2014
[email protected]127f18ec2012-06-16 05:05:592015
[email protected]e7479052012-09-19 00:26:122016def _CheckNoTrinaryTrueFalse(input_api, output_api):
2017 """Checks to make sure we don't introduce use of foo ? true : false."""
2018 problems = []
2019 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2020 for f in input_api.AffectedFiles():
2021 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2022 continue
2023
2024 for line_num, line in f.ChangedContents():
2025 if pattern.match(line):
2026 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2027
2028 if not problems:
2029 return []
2030 return [output_api.PresubmitPromptWarning(
2031 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2032 '\n'.join(problems))]
2033
2034
[email protected]55f9f382012-07-31 11:02:182035def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282036 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182037 change. Breaking - rules is an error, breaking ! rules is a
2038 warning.
2039 """
mohan.reddyf21db962014-10-16 12:26:472040 import sys
[email protected]55f9f382012-07-31 11:02:182041 # We need to wait until we have an input_api object and use this
2042 # roundabout construct to import checkdeps because this file is
2043 # eval-ed and thus doesn't have __file__.
2044 original_sys_path = sys.path
2045 try:
2046 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472047 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182048 import checkdeps
[email protected]55f9f382012-07-31 11:02:182049 from rules import Rule
2050 finally:
2051 # Restore sys.path to what it was before.
2052 sys.path = original_sys_path
2053
2054 added_includes = []
rhalavati08acd232017-04-03 07:23:282055 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242056 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182057 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062058 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502059 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082060 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062061 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502062 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082063 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062064 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502065 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082066 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182067
[email protected]26385172013-05-09 23:11:352068 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182069
2070 error_descriptions = []
2071 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282072 error_subjects = set()
2073 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182074 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2075 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082076 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182077 description_with_path = '%s\n %s' % (path, rule_description)
2078 if rule_type == Rule.DISALLOW:
2079 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282080 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182081 else:
2082 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282083 warning_subjects.add("#includes")
2084
2085 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2086 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082087 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282088 description_with_path = '%s\n %s' % (path, rule_description)
2089 if rule_type == Rule.DISALLOW:
2090 error_descriptions.append(description_with_path)
2091 error_subjects.add("imports")
2092 else:
2093 warning_descriptions.append(description_with_path)
2094 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182095
Jinsuk Kim5a092672017-10-24 22:42:242096 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022097 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082098 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242099 description_with_path = '%s\n %s' % (path, rule_description)
2100 if rule_type == Rule.DISALLOW:
2101 error_descriptions.append(description_with_path)
2102 error_subjects.add("imports")
2103 else:
2104 warning_descriptions.append(description_with_path)
2105 warning_subjects.add("imports")
2106
[email protected]55f9f382012-07-31 11:02:182107 results = []
2108 if error_descriptions:
2109 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282110 'You added one or more %s that violate checkdeps rules.'
2111 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182112 error_descriptions))
2113 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422114 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282115 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182116 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282117 '%s? See relevant DEPS file(s) for details and contacts.' %
2118 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182119 warning_descriptions))
2120 return results
2121
2122
[email protected]fbcafe5a2012-08-08 15:31:222123def _CheckFilePermissions(input_api, output_api):
2124 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152125 if input_api.platform == 'win32':
2126 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292127 checkperms_tool = input_api.os_path.join(
2128 input_api.PresubmitLocalPath(),
2129 'tools', 'checkperms', 'checkperms.py')
2130 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472131 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392132 with input_api.CreateTemporaryFile() as file_list:
2133 for f in input_api.AffectedFiles():
2134 # checkperms.py file/directory arguments must be relative to the
2135 # repository.
2136 file_list.write(f.LocalPath() + '\n')
2137 file_list.close()
2138 args += ['--file-list', file_list.name]
2139 try:
2140 input_api.subprocess.check_output(args)
2141 return []
2142 except input_api.subprocess.CalledProcessError as error:
2143 return [output_api.PresubmitError(
2144 'checkperms.py failed:',
2145 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222146
2147
robertocn832f5992017-01-04 19:01:302148def _CheckTeamTags(input_api, output_api):
2149 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2150 checkteamtags_tool = input_api.os_path.join(
2151 input_api.PresubmitLocalPath(),
2152 'tools', 'checkteamtags', 'checkteamtags.py')
2153 args = [input_api.python_executable, checkteamtags_tool,
2154 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222155 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302156 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2157 'OWNERS']
2158 try:
2159 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052160 warnings = input_api.subprocess.check_output(args + files).splitlines()
2161 if warnings:
2162 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302163 return []
2164 except input_api.subprocess.CalledProcessError as error:
2165 return [output_api.PresubmitError(
2166 'checkteamtags.py failed:',
2167 long_text=error.output)]
2168
2169
[email protected]c8278b32012-10-30 20:35:492170def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2171 """Makes sure we don't include ui/aura/window_property.h
2172 in header files.
2173 """
2174 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2175 errors = []
2176 for f in input_api.AffectedFiles():
2177 if not f.LocalPath().endswith('.h'):
2178 continue
2179 for line_num, line in f.ChangedContents():
2180 if pattern.match(line):
2181 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2182
2183 results = []
2184 if errors:
2185 results.append(output_api.PresubmitError(
2186 'Header files should not include ui/aura/window_property.h', errors))
2187 return results
2188
2189
[email protected]70ca77752012-11-20 03:45:032190def _CheckForVersionControlConflictsInFile(input_api, f):
2191 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2192 errors = []
2193 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162194 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232195 # First-level headers in markdown look a lot like version control
2196 # conflict markers. http://daringfireball.net/projects/markdown/basics
2197 continue
[email protected]70ca77752012-11-20 03:45:032198 if pattern.match(line):
2199 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2200 return errors
2201
2202
2203def _CheckForVersionControlConflicts(input_api, output_api):
2204 """Usually this is not intentional and will cause a compile failure."""
2205 errors = []
2206 for f in input_api.AffectedFiles():
2207 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2208
2209 results = []
2210 if errors:
2211 results.append(output_api.PresubmitError(
2212 'Version control conflict markers found, please resolve.', errors))
2213 return results
2214
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202215
estadee17314a02017-01-12 16:22:162216def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2217 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2218 errors = []
2219 for f in input_api.AffectedFiles():
2220 for line_num, line in f.ChangedContents():
2221 if pattern.search(line):
2222 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2223
2224 results = []
2225 if errors:
2226 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502227 'Found Google support URL addressed by answer number. Please replace '
2228 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162229 return results
2230
[email protected]70ca77752012-11-20 03:45:032231
[email protected]06e6d0ff2012-12-11 01:36:442232def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2233 def FilterFile(affected_file):
2234 """Filter function for use with input_api.AffectedSourceFiles,
2235 below. This filters out everything except non-test files from
2236 top-level directories that generally speaking should not hard-code
2237 service URLs (e.g. src/android_webview/, src/content/ and others).
2238 """
2239 return input_api.FilterSourceFile(
2240 affected_file,
Egor Paskoce145c42018-09-28 19:31:042241 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442242 black_list=(_EXCLUDED_PATHS +
2243 _TEST_CODE_EXCLUDED_PATHS +
2244 input_api.DEFAULT_BLACK_LIST))
2245
reillyi38965732015-11-16 18:27:332246 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2247 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462248 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2249 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442250 problems = [] # items are (filename, line_number, line)
2251 for f in input_api.AffectedSourceFiles(FilterFile):
2252 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462253 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442254 problems.append((f.LocalPath(), line_num, line))
2255
2256 if problems:
[email protected]f7051d52013-04-02 18:31:422257 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442258 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582259 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442260 [' %s:%d: %s' % (
2261 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032262 else:
2263 return []
[email protected]06e6d0ff2012-12-11 01:36:442264
2265
James Cook6b6597c2019-11-06 22:05:292266def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2267 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2268 def FileFilter(affected_file):
2269 """Includes directories known to be Chrome OS only."""
2270 return input_api.FilterSourceFile(
2271 affected_file,
2272 white_list=('^ash/',
2273 '^chromeos/', # Top-level src/chromeos.
2274 '/chromeos/', # Any path component.
2275 '^components/arc',
2276 '^components/exo'),
2277 black_list=(input_api.DEFAULT_BLACK_LIST))
2278
2279 prefs = []
2280 priority_prefs = []
2281 for f in input_api.AffectedFiles(file_filter=FileFilter):
2282 for line_num, line in f.ChangedContents():
2283 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2284 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2285 prefs.append(' %s' % line)
2286 if input_api.re.search(
2287 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2288 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2289 priority_prefs.append(' %s' % line)
2290
2291 results = []
2292 if (prefs):
2293 results.append(output_api.PresubmitPromptWarning(
2294 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2295 'by browser sync settings. If these prefs should be controlled by OS '
2296 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2297 if (priority_prefs):
2298 results.append(output_api.PresubmitPromptWarning(
2299 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2300 'controlled by browser sync settings. If these prefs should be '
2301 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2302 'instead.\n' + '\n'.join(prefs)))
2303 return results
2304
2305
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492306# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272307def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2308 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312309 The native_client_sdk directory is excluded because it has auto-generated PNG
2310 files for documentation.
[email protected]d2530012013-01-25 16:39:272311 """
[email protected]d2530012013-01-25 16:39:272312 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492313 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042314 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312315 file_filter = lambda f: input_api.FilterSourceFile(
2316 f, white_list=white_list, black_list=black_list)
2317 for f in input_api.AffectedFiles(include_deletes=False,
2318 file_filter=file_filter):
2319 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272320
2321 results = []
2322 if errors:
2323 results.append(output_api.PresubmitError(
2324 'The name of PNG files should not have abbreviations. \n'
2325 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2326 'Contact [email protected] if you have questions.', errors))
2327 return results
2328
2329
Daniel Cheng4dcdb6b2017-04-13 08:30:172330def _ExtractAddRulesFromParsedDeps(parsed_deps):
2331 """Extract the rules that add dependencies from a parsed DEPS file.
2332
2333 Args:
2334 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2335 add_rules = set()
2336 add_rules.update([
2337 rule[1:] for rule in parsed_deps.get('include_rules', [])
2338 if rule.startswith('+') or rule.startswith('!')
2339 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502340 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172341 {}).iteritems():
2342 add_rules.update([
2343 rule[1:] for rule in rules
2344 if rule.startswith('+') or rule.startswith('!')
2345 ])
2346 return add_rules
2347
2348
2349def _ParseDeps(contents):
2350 """Simple helper for parsing DEPS files."""
2351 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172352 class _VarImpl:
2353
2354 def __init__(self, local_scope):
2355 self._local_scope = local_scope
2356
2357 def Lookup(self, var_name):
2358 """Implements the Var syntax."""
2359 try:
2360 return self._local_scope['vars'][var_name]
2361 except KeyError:
2362 raise Exception('Var is not defined: %s' % var_name)
2363
2364 local_scope = {}
2365 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172366 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592367 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172368 }
2369 exec contents in global_scope, local_scope
2370 return local_scope
2371
2372
2373def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082374 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412375 a set of DEPS entries that we should look up.
2376
2377 For a directory (rather than a specific filename) we fake a path to
2378 a specific filename by adding /DEPS. This is chosen as a file that
2379 will seldom or never be subject to per-file include_rules.
2380 """
[email protected]2b438d62013-11-14 17:54:142381 # We ignore deps entries on auto-generated directories.
2382 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082383
Daniel Cheng4dcdb6b2017-04-13 08:30:172384 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2385 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2386
2387 added_deps = new_deps.difference(old_deps)
2388
[email protected]2b438d62013-11-14 17:54:142389 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172390 for added_dep in added_deps:
2391 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2392 continue
2393 # Assume that a rule that ends in .h is a rule for a specific file.
2394 if added_dep.endswith('.h'):
2395 results.add(added_dep)
2396 else:
2397 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082398 return results
2399
2400
[email protected]e871964c2013-05-13 14:14:552401def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2402 """When a dependency prefixed with + is added to a DEPS file, we
2403 want to make sure that the change is reviewed by an OWNER of the
2404 target file or directory, to avoid layering violations from being
2405 introduced. This check verifies that this happens.
2406 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172407 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242408
2409 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492410 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242411 for f in input_api.AffectedFiles(include_deletes=False,
2412 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552413 filename = input_api.os_path.basename(f.LocalPath())
2414 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172415 virtual_depended_on_files.update(_CalculateAddedDeps(
2416 input_api.os_path,
2417 '\n'.join(f.OldContents()),
2418 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552419
[email protected]e871964c2013-05-13 14:14:552420 if not virtual_depended_on_files:
2421 return []
2422
2423 if input_api.is_committing:
2424 if input_api.tbr:
2425 return [output_api.PresubmitNotifyResult(
2426 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272427 if input_api.dry_run:
2428 return [output_api.PresubmitNotifyResult(
2429 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552430 if not input_api.change.issue:
2431 return [output_api.PresubmitError(
2432 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402433 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552434 output = output_api.PresubmitError
2435 else:
2436 output = output_api.PresubmitNotifyResult
2437
2438 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502439 owner_email, reviewers = (
2440 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2441 input_api,
2442 owners_db.email_regexp,
2443 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552444
2445 owner_email = owner_email or input_api.change.author_email
2446
[email protected]de4f7d22013-05-23 14:27:462447 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512448 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462449 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552450 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2451 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412452
2453 # We strip the /DEPS part that was added by
2454 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2455 # directory.
2456 def StripDeps(path):
2457 start_deps = path.rfind('/DEPS')
2458 if start_deps != -1:
2459 return path[:start_deps]
2460 else:
2461 return path
2462 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552463 for path in missing_files]
2464
2465 if unapproved_dependencies:
2466 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152467 output('You need LGTM from owners of depends-on paths in DEPS that were '
2468 'modified in this CL:\n %s' %
2469 '\n '.join(sorted(unapproved_dependencies)))]
2470 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2471 output_list.append(output(
2472 'Suggested missing target path OWNERS:\n %s' %
2473 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552474 return output_list
2475
2476 return []
2477
2478
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492479# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402480def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492481 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402482 black_list = (_EXCLUDED_PATHS +
2483 _TEST_CODE_EXCLUDED_PATHS +
2484 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042485 (r"^base[\\/]logging\.h$",
2486 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222487 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042488 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2489 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2490 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122491 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182492 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152493 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032494 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152495 r"^chrome[\\/]chrome_cleaner[\\/].*",
2496 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2497 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042498 r"^chromecast[\\/]",
2499 r"^cloud_print[\\/]",
2500 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482501 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052502 r"^components[\\/]media_control[\\/]renderer[\\/]"
2503 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042504 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462505 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042506 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462507 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042508 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252509 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042510 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2511 r"^courgette[\\/]courgette_tool\.cc$",
2512 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272513 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002514 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332515 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042516 r"^ipc[\\/]ipc_logging\.cc$",
2517 r"^native_client_sdk[\\/]",
2518 r"^remoting[\\/]base[\\/]logging\.h$",
2519 r"^remoting[\\/]host[\\/].*",
2520 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062521 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332522 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042523 r"^tools[\\/]",
2524 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2525 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:372526 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2527 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2528 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402529 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492530 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402531
thomasanderson625d3932017-03-29 07:16:582532 log_info = set([])
2533 printf = set([])
[email protected]85218562013-11-22 07:41:402534
2535 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582536 for _, line in f.ChangedContents():
2537 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2538 log_info.add(f.LocalPath())
2539 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2540 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372541
thomasanderson625d3932017-03-29 07:16:582542 if input_api.re.search(r"\bprintf\(", line):
2543 printf.add(f.LocalPath())
2544 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2545 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402546
2547 if log_info:
2548 return [output_api.PresubmitError(
2549 'These files spam the console log with LOG(INFO):',
2550 items=log_info)]
2551 if printf:
2552 return [output_api.PresubmitError(
2553 'These files spam the console log with printf/fprintf:',
2554 items=printf)]
2555 return []
2556
2557
[email protected]49aa76a2013-12-04 06:59:162558def _CheckForAnonymousVariables(input_api, output_api):
2559 """These types are all expected to hold locks while in scope and
2560 so should never be anonymous (which causes them to be immediately
2561 destroyed)."""
2562 they_who_must_be_named = [
2563 'base::AutoLock',
2564 'base::AutoReset',
2565 'base::AutoUnlock',
2566 'SkAutoAlphaRestore',
2567 'SkAutoBitmapShaderInstall',
2568 'SkAutoBlitterChoose',
2569 'SkAutoBounderCommit',
2570 'SkAutoCallProc',
2571 'SkAutoCanvasRestore',
2572 'SkAutoCommentBlock',
2573 'SkAutoDescriptor',
2574 'SkAutoDisableDirectionCheck',
2575 'SkAutoDisableOvalCheck',
2576 'SkAutoFree',
2577 'SkAutoGlyphCache',
2578 'SkAutoHDC',
2579 'SkAutoLockColors',
2580 'SkAutoLockPixels',
2581 'SkAutoMalloc',
2582 'SkAutoMaskFreeImage',
2583 'SkAutoMutexAcquire',
2584 'SkAutoPathBoundsUpdate',
2585 'SkAutoPDFRelease',
2586 'SkAutoRasterClipValidate',
2587 'SkAutoRef',
2588 'SkAutoTime',
2589 'SkAutoTrace',
2590 'SkAutoUnref',
2591 ]
2592 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2593 # bad: base::AutoLock(lock.get());
2594 # not bad: base::AutoLock lock(lock.get());
2595 bad_pattern = input_api.re.compile(anonymous)
2596 # good: new base::AutoLock(lock.get())
2597 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2598 errors = []
2599
2600 for f in input_api.AffectedFiles():
2601 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2602 continue
2603 for linenum, line in f.ChangedContents():
2604 if bad_pattern.search(line) and not good_pattern.search(line):
2605 errors.append('%s:%d' % (f.LocalPath(), linenum))
2606
2607 if errors:
2608 return [output_api.PresubmitError(
2609 'These lines create anonymous variables that need to be named:',
2610 items=errors)]
2611 return []
2612
2613
Peter Kasting4844e46e2018-02-23 07:27:102614def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532615 # Returns whether |template_str| is of the form <T, U...> for some types T
2616 # and U. Assumes that |template_str| is already in the form <...>.
2617 def HasMoreThanOneArg(template_str):
2618 # Level of <...> nesting.
2619 nesting = 0
2620 for c in template_str:
2621 if c == '<':
2622 nesting += 1
2623 elif c == '>':
2624 nesting -= 1
2625 elif c == ',' and nesting == 1:
2626 return True
2627 return False
2628
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492629 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102630 sources = lambda affected_file: input_api.FilterSourceFile(
2631 affected_file,
2632 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2633 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492634 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552635
2636 # Pattern to capture a single "<...>" block of template arguments. It can
2637 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2638 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2639 # latter would likely require counting that < and > match, which is not
2640 # expressible in regular languages. Should the need arise, one can introduce
2641 # limited counting (matching up to a total number of nesting depth), which
2642 # should cover all practical cases for already a low nesting limit.
2643 template_arg_pattern = (
2644 r'<[^>]*' # Opening block of <.
2645 r'>([^<]*>)?') # Closing block of >.
2646 # Prefix expressing that whatever follows is not already inside a <...>
2647 # block.
2648 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102649 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552650 not_inside_template_arg_pattern
2651 + r'\bstd::unique_ptr'
2652 + template_arg_pattern
2653 + r'\(\)')
2654
2655 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2656 template_arg_no_array_pattern = (
2657 r'<[^>]*[^]]' # Opening block of <.
2658 r'>([^(<]*[^]]>)?') # Closing block of >.
2659 # Prefix saying that what follows is the start of an expression.
2660 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2661 # Suffix saying that what follows are call parentheses with a non-empty list
2662 # of arguments.
2663 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532664 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552665 return_construct_pattern = input_api.re.compile(
2666 start_of_expr_pattern
2667 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532668 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552669 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532670 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552671 + nonempty_arg_list_pattern)
2672
Vaclav Brozek851d9602018-04-04 16:13:052673 problems_constructor = []
2674 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102675 for f in input_api.AffectedSourceFiles(sources):
2676 for line_number, line in f.ChangedContents():
2677 # Disallow:
2678 # return std::unique_ptr<T>(foo);
2679 # bar = std::unique_ptr<T>(foo);
2680 # But allow:
2681 # return std::unique_ptr<T[]>(foo);
2682 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532683 # And also allow cases when the second template argument is present. Those
2684 # cases cannot be handled by std::make_unique:
2685 # return std::unique_ptr<T, U>(foo);
2686 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052687 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532688 return_construct_result = return_construct_pattern.search(line)
2689 if return_construct_result and not HasMoreThanOneArg(
2690 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052691 problems_constructor.append(
2692 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102693 # Disallow:
2694 # std::unique_ptr<T>()
2695 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052696 problems_nullptr.append(
2697 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2698
2699 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162700 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052701 errors.append(output_api.PresubmitError(
2702 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162703 problems_nullptr))
2704 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052705 errors.append(output_api.PresubmitError(
2706 'The following files use explicit std::unique_ptr constructor.'
2707 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162708 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102709 return errors
2710
2711
[email protected]999261d2014-03-03 20:08:082712def _CheckUserActionUpdate(input_api, output_api):
2713 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522714 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082715 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522716 # If actions.xml is already included in the changelist, the PRESUBMIT
2717 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082718 return []
2719
[email protected]999261d2014-03-03 20:08:082720 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2721 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522722 current_actions = None
[email protected]999261d2014-03-03 20:08:082723 for f in input_api.AffectedFiles(file_filter=file_filter):
2724 for line_num, line in f.ChangedContents():
2725 match = input_api.re.search(action_re, line)
2726 if match:
[email protected]2f92dec2014-03-07 19:21:522727 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2728 # loaded only once.
2729 if not current_actions:
2730 with open('tools/metrics/actions/actions.xml') as actions_f:
2731 current_actions = actions_f.read()
2732 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082733 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522734 action = 'name="{0}"'.format(action_name)
2735 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082736 return [output_api.PresubmitPromptWarning(
2737 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522738 'tools/metrics/actions/actions.xml. Please run '
2739 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082740 % (f.LocalPath(), line_num, action_name))]
2741 return []
2742
2743
Daniel Cheng13ca61a882017-08-25 15:11:252744def _ImportJSONCommentEater(input_api):
2745 import sys
2746 sys.path = sys.path + [input_api.os_path.join(
2747 input_api.PresubmitLocalPath(),
2748 'tools', 'json_comment_eater')]
2749 import json_comment_eater
2750 return json_comment_eater
2751
2752
[email protected]99171a92014-06-03 08:44:472753def _GetJSONParseError(input_api, filename, eat_comments=True):
2754 try:
2755 contents = input_api.ReadFile(filename)
2756 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252757 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132758 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472759
2760 input_api.json.loads(contents)
2761 except ValueError as e:
2762 return e
2763 return None
2764
2765
2766def _GetIDLParseError(input_api, filename):
2767 try:
2768 contents = input_api.ReadFile(filename)
2769 idl_schema = input_api.os_path.join(
2770 input_api.PresubmitLocalPath(),
2771 'tools', 'json_schema_compiler', 'idl_schema.py')
2772 process = input_api.subprocess.Popen(
2773 [input_api.python_executable, idl_schema],
2774 stdin=input_api.subprocess.PIPE,
2775 stdout=input_api.subprocess.PIPE,
2776 stderr=input_api.subprocess.PIPE,
2777 universal_newlines=True)
2778 (_, error) = process.communicate(input=contents)
2779 return error or None
2780 except ValueError as e:
2781 return e
2782
2783
2784def _CheckParseErrors(input_api, output_api):
2785 """Check that IDL and JSON files do not contain syntax errors."""
2786 actions = {
2787 '.idl': _GetIDLParseError,
2788 '.json': _GetJSONParseError,
2789 }
[email protected]99171a92014-06-03 08:44:472790 # Most JSON files are preprocessed and support comments, but these do not.
2791 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042792 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472793 ]
2794 # Only run IDL checker on files in these directories.
2795 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042796 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2797 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472798 ]
2799
2800 def get_action(affected_file):
2801 filename = affected_file.LocalPath()
2802 return actions.get(input_api.os_path.splitext(filename)[1])
2803
[email protected]99171a92014-06-03 08:44:472804 def FilterFile(affected_file):
2805 action = get_action(affected_file)
2806 if not action:
2807 return False
2808 path = affected_file.LocalPath()
2809
Erik Staab2dd72b12020-04-16 15:03:402810 if _MatchesFile(input_api,
2811 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2812 path):
[email protected]99171a92014-06-03 08:44:472813 return False
2814
2815 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162816 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472817 return False
2818 return True
2819
2820 results = []
2821 for affected_file in input_api.AffectedFiles(
2822 file_filter=FilterFile, include_deletes=False):
2823 action = get_action(affected_file)
2824 kwargs = {}
2825 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162826 _MatchesFile(input_api, json_no_comments_patterns,
2827 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472828 kwargs['eat_comments'] = False
2829 parse_error = action(input_api,
2830 affected_file.AbsoluteLocalPath(),
2831 **kwargs)
2832 if parse_error:
2833 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2834 (affected_file.LocalPath(), parse_error)))
2835 return results
2836
2837
[email protected]760deea2013-12-10 19:33:492838def _CheckJavaStyle(input_api, output_api):
2839 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472840 import sys
[email protected]760deea2013-12-10 19:33:492841 original_sys_path = sys.path
2842 try:
2843 sys.path = sys.path + [input_api.os_path.join(
2844 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2845 import checkstyle
2846 finally:
2847 # Restore sys.path to what it was before.
2848 sys.path = original_sys_path
2849
2850 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092851 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512852 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492853
2854
Nate Fischerdfd9812e2019-07-18 22:03:002855def _CheckPythonDevilInit(input_api, output_api):
2856 """Checks to make sure devil is initialized correctly in python scripts."""
2857 script_common_initialize_pattern = input_api.re.compile(
2858 r'script_common\.InitializeEnvironment\(')
2859 devil_env_config_initialize = input_api.re.compile(
2860 r'devil_env\.config\.Initialize\(')
2861
2862 errors = []
2863
2864 sources = lambda affected_file: input_api.FilterSourceFile(
2865 affected_file,
2866 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2867 (r'^build[\\/]android[\\/]devil_chromium\.py',
2868 r'^third_party[\\/].*',)),
2869 white_list=[r'.*\.py$'])
2870
2871 for f in input_api.AffectedSourceFiles(sources):
2872 for line_num, line in f.ChangedContents():
2873 if (script_common_initialize_pattern.search(line) or
2874 devil_env_config_initialize.search(line)):
2875 errors.append("%s:%d" % (f.LocalPath(), line_num))
2876
2877 results = []
2878
2879 if errors:
2880 results.append(output_api.PresubmitError(
2881 'Devil initialization should always be done using '
2882 'devil_chromium.Initialize() in the chromium project, to use better '
2883 'defaults for dependencies (ex. up-to-date version of adb).',
2884 errors))
2885
2886 return results
2887
2888
Sean Kau46e29bc2017-08-28 16:31:162889def _MatchesFile(input_api, patterns, path):
2890 for pattern in patterns:
2891 if input_api.re.search(pattern, path):
2892 return True
2893 return False
2894
2895
Daniel Cheng7052cdf2017-11-21 19:23:292896def _GetOwnersFilesToCheckForIpcOwners(input_api):
2897 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172898
Daniel Cheng7052cdf2017-11-21 19:23:292899 Returns:
2900 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2901 contain to cover IPC-related files with noparent reviewer rules.
2902 """
2903 # Whether or not a file affects IPC is (mostly) determined by a simple list
2904 # of filename patterns.
dchenge07de812016-06-20 19:27:172905 file_patterns = [
palmerb19a0932017-01-24 04:00:312906 # Legacy IPC:
dchenge07de812016-06-20 19:27:172907 '*_messages.cc',
2908 '*_messages*.h',
2909 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312910 # Mojo IPC:
dchenge07de812016-06-20 19:27:172911 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472912 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172913 '*_struct_traits*.*',
2914 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312915 '*.typemap',
2916 # Android native IPC:
2917 '*.aidl',
2918 # Blink uses a different file naming convention:
2919 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472920 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172921 '*StructTraits*.*',
2922 '*TypeConverter*.*',
2923 ]
2924
scottmg7a6ed5ba2016-11-04 18:22:042925 # These third_party directories do not contain IPCs, but contain files
2926 # matching the above patterns, which trigger false positives.
2927 exclude_paths = [
2928 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162929 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232930 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292931 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542932 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162933 # These files are just used to communicate between class loaders running
2934 # in the same process.
2935 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572936 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2937
scottmg7a6ed5ba2016-11-04 18:22:042938 ]
2939
dchenge07de812016-06-20 19:27:172940 # Dictionary mapping an OWNERS file path to Patterns.
2941 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2942 # rules ) to a PatternEntry.
2943 # PatternEntry is a dictionary with two keys:
2944 # - 'files': the files that are matched by this pattern
2945 # - 'rules': the per-file rules needed for this pattern
2946 # For example, if we expect OWNERS file to contain rules for *.mojom and
2947 # *_struct_traits*.*, Patterns might look like this:
2948 # {
2949 # '*.mojom': {
2950 # 'files': ...,
2951 # 'rules': [
2952 # 'per-file *.mojom=set noparent',
2953 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2954 # ],
2955 # },
2956 # '*_struct_traits*.*': {
2957 # 'files': ...,
2958 # 'rules': [
2959 # 'per-file *_struct_traits*.*=set noparent',
2960 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2961 # ],
2962 # },
2963 # }
2964 to_check = {}
2965
Daniel Cheng13ca61a882017-08-25 15:11:252966 def AddPatternToCheck(input_file, pattern):
2967 owners_file = input_api.os_path.join(
2968 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2969 if owners_file not in to_check:
2970 to_check[owners_file] = {}
2971 if pattern not in to_check[owners_file]:
2972 to_check[owners_file][pattern] = {
2973 'files': [],
2974 'rules': [
2975 'per-file %s=set noparent' % pattern,
2976 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2977 ]
2978 }
Vaclav Brozekd5de76a2018-03-17 07:57:502979 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252980
dchenge07de812016-06-20 19:27:172981 # Iterate through the affected files to see what we actually need to check
2982 # for. We should only nag patch authors about per-file rules if a file in that
2983 # directory would match that pattern. If a directory only contains *.mojom
2984 # files and no *_messages*.h files, we should only nag about rules for
2985 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252986 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262987 # Manifest files don't have a strong naming convention. Instead, try to find
2988 # affected .cc and .h files which look like they contain a manifest
2989 # definition.
2990 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2991 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2992 if (manifest_pattern.search(f.LocalPath()) and not
2993 test_manifest_pattern.search(f.LocalPath())):
2994 # We expect all actual service manifest files to contain at least one
2995 # qualified reference to service_manager::Manifest.
2996 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252997 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172998 for pattern in file_patterns:
2999 if input_api.fnmatch.fnmatch(
3000 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043001 skip = False
3002 for exclude in exclude_paths:
3003 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3004 skip = True
3005 break
3006 if skip:
3007 continue
Daniel Cheng13ca61a882017-08-25 15:11:253008 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173009 break
3010
Daniel Cheng7052cdf2017-11-21 19:23:293011 return to_check
3012
3013
Wez17c66962020-04-29 15:26:033014def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3015 """Adds OWNERS files to check for correct Fuchsia security owners."""
3016
3017 file_patterns = [
3018 # Component specifications.
3019 '*.cml', # Component Framework v2.
3020 '*.cmx', # Component Framework v1.
3021
3022 # Fuchsia IDL protocol specifications.
3023 '*.fidl',
3024 ]
3025
3026 def AddPatternToCheck(input_file, pattern):
3027 owners_file = input_api.os_path.join(
3028 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3029 if owners_file not in to_check:
3030 to_check[owners_file] = {}
3031 if pattern not in to_check[owners_file]:
3032 to_check[owners_file][pattern] = {
3033 'files': [],
3034 'rules': [
3035 'per-file %s=set noparent' % pattern,
3036 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3037 ]
3038 }
3039 to_check[owners_file][pattern]['files'].append(input_file)
3040
3041 # Iterate through the affected files to see what we actually need to check
3042 # for. We should only nag patch authors about per-file rules if a file in that
3043 # directory would match that pattern.
3044 for f in input_api.AffectedFiles(include_deletes=False):
3045 for pattern in file_patterns:
3046 if input_api.fnmatch.fnmatch(
3047 input_api.os_path.basename(f.LocalPath()), pattern):
3048 AddPatternToCheck(f, pattern)
3049 break
3050
3051 return to_check
3052
3053
3054def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293055 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3056 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033057 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293058
3059 if to_check:
3060 # If there are any OWNERS files to check, there are IPC-related changes in
3061 # this CL. Auto-CC the review list.
3062 output_api.AppendCC('[email protected]')
3063
3064 # Go through the OWNERS files to check, filtering out rules that are already
3065 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173066 for owners_file, patterns in to_check.iteritems():
3067 try:
3068 with file(owners_file) as f:
3069 lines = set(f.read().splitlines())
3070 for entry in patterns.itervalues():
3071 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3072 ]
3073 except IOError:
3074 # No OWNERS file, so all the rules are definitely missing.
3075 continue
3076
3077 # All the remaining lines weren't found in OWNERS files, so emit an error.
3078 errors = []
3079 for owners_file, patterns in to_check.iteritems():
3080 missing_lines = []
3081 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503082 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173083 missing_lines.extend(entry['rules'])
3084 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3085 if missing_lines:
3086 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053087 'Because of the presence of files:\n%s\n\n'
3088 '%s needs the following %d lines added:\n\n%s' %
3089 ('\n'.join(files), owners_file, len(missing_lines),
3090 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173091
3092 results = []
3093 if errors:
vabrf5ce3bf92016-07-11 14:52:413094 if input_api.is_committing:
3095 output = output_api.PresubmitError
3096 else:
3097 output = output_api.PresubmitPromptWarning
3098 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593099 'Found OWNERS files that need to be updated for IPC security ' +
3100 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173101 long_text='\n\n'.join(errors)))
3102
3103 return results
3104
3105
Robert Sesek2c905332020-05-06 23:17:133106def _GetFilesUsingSecurityCriticalFunctions(input_api):
3107 """Checks affected files for changes to security-critical calls. This
3108 function checks the full change diff, to catch both additions/changes
3109 and removals.
3110
3111 Returns a dict keyed by file name, and the value is a set of detected
3112 functions.
3113 """
3114 # Map of function pretty name (displayed in an error) to the pattern to
3115 # match it with.
3116 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373117 'content::GetServiceSandboxType<>()':
3118 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133119 }
3120 _PATTERNS_TO_CHECK = {
3121 k: input_api.re.compile(v)
3122 for k, v in _PATTERNS_TO_CHECK.items()
3123 }
3124
3125 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3126 files_to_functions = {}
3127 for f in input_api.AffectedFiles():
3128 diff = f.GenerateScmDiff()
3129 for line in diff.split('\n'):
3130 # Not using just RightHandSideLines() because removing a
3131 # call to a security-critical function can be just as important
3132 # as adding or changing the arguments.
3133 if line.startswith('-') or (line.startswith('+') and
3134 not line.startswith('++')):
3135 for name, pattern in _PATTERNS_TO_CHECK.items():
3136 if pattern.search(line):
3137 path = f.LocalPath()
3138 if not path in files_to_functions:
3139 files_to_functions[path] = set()
3140 files_to_functions[path].add(name)
3141 return files_to_functions
3142
3143
3144def _CheckSecurityChanges(input_api, output_api):
3145 """Checks that changes involving security-critical functions are reviewed
3146 by the security team.
3147 """
3148 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3149 if len(files_to_functions):
3150 owners_db = input_api.owners_db
3151 owner_email, reviewers = (
3152 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3153 input_api,
3154 owners_db.email_regexp,
3155 approval_needed=input_api.is_committing))
3156
3157 # Load the OWNERS file for security changes.
3158 owners_file = 'ipc/SECURITY_OWNERS'
3159 security_owners = owners_db.owners_rooted_at_file(owners_file)
3160
3161 has_security_owner = any([owner in reviewers for owner in security_owners])
3162 if not has_security_owner:
3163 msg = 'The following files change calls to security-sensive functions\n' \
3164 'that need to be reviewed by {}.\n'.format(owners_file)
3165 for path, names in files_to_functions.items():
3166 msg += ' {}\n'.format(path)
3167 for name in names:
3168 msg += ' {}\n'.format(name)
3169 msg += '\n'
3170
3171 if input_api.is_committing:
3172 output = output_api.PresubmitError
3173 else:
3174 output = output_api.PresubmitNotifyResult
3175 return [output(msg)]
3176
3177 return []
3178
3179
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263180def _CheckSetNoParent(input_api, output_api):
3181 """Checks that set noparent is only used together with an OWNERS file in
3182 //build/OWNERS.setnoparent (see also
3183 //docs/code_reviews.md#owners-files-details)
3184 """
3185 errors = []
3186
3187 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3188 allowed_owners_files = set()
3189 with open(allowed_owners_files_file, 'r') as f:
3190 for line in f:
3191 line = line.strip()
3192 if not line or line.startswith('#'):
3193 continue
3194 allowed_owners_files.add(line)
3195
3196 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3197
3198 for f in input_api.AffectedFiles(include_deletes=False):
3199 if not f.LocalPath().endswith('OWNERS'):
3200 continue
3201
3202 found_owners_files = set()
3203 found_set_noparent_lines = dict()
3204
3205 # Parse the OWNERS file.
3206 for lineno, line in enumerate(f.NewContents(), 1):
3207 line = line.strip()
3208 if line.startswith('set noparent'):
3209 found_set_noparent_lines[''] = lineno
3210 if line.startswith('file://'):
3211 if line in allowed_owners_files:
3212 found_owners_files.add('')
3213 if line.startswith('per-file'):
3214 match = per_file_pattern.match(line)
3215 if match:
3216 glob = match.group(1).strip()
3217 directive = match.group(2).strip()
3218 if directive == 'set noparent':
3219 found_set_noparent_lines[glob] = lineno
3220 if directive.startswith('file://'):
3221 if directive in allowed_owners_files:
3222 found_owners_files.add(glob)
3223
3224 # Check that every set noparent line has a corresponding file:// line
3225 # listed in build/OWNERS.setnoparent.
3226 for set_noparent_line in found_set_noparent_lines:
3227 if set_noparent_line in found_owners_files:
3228 continue
3229 errors.append(' %s:%d' % (f.LocalPath(),
3230 found_set_noparent_lines[set_noparent_line]))
3231
3232 results = []
3233 if errors:
3234 if input_api.is_committing:
3235 output = output_api.PresubmitError
3236 else:
3237 output = output_api.PresubmitPromptWarning
3238 results.append(output(
3239 'Found the following "set noparent" restrictions in OWNERS files that '
3240 'do not include owners from build/OWNERS.setnoparent:',
3241 long_text='\n\n'.join(errors)))
3242 return results
3243
3244
jbriance9e12f162016-11-25 07:57:503245def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313246 """Checks that added or removed lines in non third party affected
3247 header files do not lead to new useless class or struct forward
3248 declaration.
jbriance9e12f162016-11-25 07:57:503249 """
3250 results = []
3251 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3252 input_api.re.MULTILINE)
3253 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3254 input_api.re.MULTILINE)
3255 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313256 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193257 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493258 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313259 continue
3260
jbriance9e12f162016-11-25 07:57:503261 if not f.LocalPath().endswith('.h'):
3262 continue
3263
3264 contents = input_api.ReadFile(f)
3265 fwd_decls = input_api.re.findall(class_pattern, contents)
3266 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3267
3268 useless_fwd_decls = []
3269 for decl in fwd_decls:
3270 count = sum(1 for _ in input_api.re.finditer(
3271 r'\b%s\b' % input_api.re.escape(decl), contents))
3272 if count == 1:
3273 useless_fwd_decls.append(decl)
3274
3275 if not useless_fwd_decls:
3276 continue
3277
3278 for line in f.GenerateScmDiff().splitlines():
3279 if (line.startswith('-') and not line.startswith('--') or
3280 line.startswith('+') and not line.startswith('++')):
3281 for decl in useless_fwd_decls:
3282 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3283 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243284 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503285 (f.LocalPath(), decl)))
3286 useless_fwd_decls.remove(decl)
3287
3288 return results
3289
Jinsong Fan91ebbbd2019-04-16 14:57:173290def _CheckAndroidDebuggableBuild(input_api, output_api):
3291 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3292 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3293 this is a debuggable build of Android.
3294 """
3295 build_type_check_pattern = input_api.re.compile(
3296 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3297
3298 errors = []
3299
3300 sources = lambda affected_file: input_api.FilterSourceFile(
3301 affected_file,
3302 black_list=(_EXCLUDED_PATHS +
3303 _TEST_CODE_EXCLUDED_PATHS +
3304 input_api.DEFAULT_BLACK_LIST +
3305 (r"^android_webview[\\/]support_library[\\/]"
3306 "boundary_interfaces[\\/]",
3307 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3308 r'^third_party[\\/].*',
3309 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3310 r"webview[\\/]chromium[\\/]License.*",)),
3311 white_list=[r'.*\.java$'])
3312
3313 for f in input_api.AffectedSourceFiles(sources):
3314 for line_num, line in f.ChangedContents():
3315 if build_type_check_pattern.search(line):
3316 errors.append("%s:%d" % (f.LocalPath(), line_num))
3317
3318 results = []
3319
3320 if errors:
3321 results.append(output_api.PresubmitPromptWarning(
3322 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3323 ' Please use BuildInfo.isDebugAndroid() instead.',
3324 errors))
3325
3326 return results
jbriance9e12f162016-11-25 07:57:503327
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493328# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293329def _CheckAndroidToastUsage(input_api, output_api):
3330 """Checks that code uses org.chromium.ui.widget.Toast instead of
3331 android.widget.Toast (Chromium Toast doesn't force hardware
3332 acceleration on low-end devices, saving memory).
3333 """
3334 toast_import_pattern = input_api.re.compile(
3335 r'^import android\.widget\.Toast;$')
3336
3337 errors = []
3338
3339 sources = lambda affected_file: input_api.FilterSourceFile(
3340 affected_file,
3341 black_list=(_EXCLUDED_PATHS +
3342 _TEST_CODE_EXCLUDED_PATHS +
3343 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043344 (r'^chromecast[\\/].*',
3345 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493346 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293347
3348 for f in input_api.AffectedSourceFiles(sources):
3349 for line_num, line in f.ChangedContents():
3350 if toast_import_pattern.search(line):
3351 errors.append("%s:%d" % (f.LocalPath(), line_num))
3352
3353 results = []
3354
3355 if errors:
3356 results.append(output_api.PresubmitError(
3357 'android.widget.Toast usage is detected. Android toasts use hardware'
3358 ' acceleration, and can be\ncostly on low-end devices. Please use'
3359 ' org.chromium.ui.widget.Toast instead.\n'
3360 'Contact [email protected] if you have any questions.',
3361 errors))
3362
3363 return results
3364
3365
dgnaa68d5e2015-06-10 10:08:223366def _CheckAndroidCrLogUsage(input_api, output_api):
3367 """Checks that new logs using org.chromium.base.Log:
3368 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513369 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223370 """
pkotwicza1dd0b002016-05-16 14:41:043371
torne89540622017-03-24 19:41:303372 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043373 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303374 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043375 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303376 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043377 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3378 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093379 # The customtabs_benchmark is a small app that does not depend on Chromium
3380 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043381 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043382 ]
3383
dgnaa68d5e2015-06-10 10:08:223384 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123385 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3386 class_in_base_pattern = input_api.re.compile(
3387 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3388 has_some_log_import_pattern = input_api.re.compile(
3389 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223390 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553391 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223392 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463393 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553394 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223395
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463396 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493397 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043398 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123399
dgnaa68d5e2015-06-10 10:08:223400 tag_decl_errors = []
3401 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123402 tag_errors = []
dgn38736db2015-09-18 19:20:513403 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123404 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223405
3406 for f in input_api.AffectedSourceFiles(sources):
3407 file_content = input_api.ReadFile(f)
3408 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223409 # Per line checks
dgn87d9fb62015-06-12 09:15:123410 if (cr_log_import_pattern.search(file_content) or
3411 (class_in_base_pattern.search(file_content) and
3412 not has_some_log_import_pattern.search(file_content))):
3413 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223414 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553415 if rough_log_decl_pattern.search(line):
3416 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223417
3418 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123419 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223420 if match:
3421 has_modified_logs = True
3422
3423 # Make sure it uses "TAG"
3424 if not match.group('tag') == 'TAG':
3425 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123426 else:
3427 # Report non cr Log function calls in changed lines
3428 for line_num, line in f.ChangedContents():
3429 if log_call_pattern.search(line):
3430 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223431
3432 # Per file checks
3433 if has_modified_logs:
3434 # Make sure the tag is using the "cr" prefix and is not too long
3435 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513436 tag_name = match.group('name') if match else None
3437 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223438 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513439 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223440 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513441 elif '.' in tag_name:
3442 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223443
3444 results = []
3445 if tag_decl_errors:
3446 results.append(output_api.PresubmitPromptWarning(
3447 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513448 '"private static final String TAG = "<package tag>".\n'
3449 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223450 tag_decl_errors))
3451
3452 if tag_length_errors:
3453 results.append(output_api.PresubmitError(
3454 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513455 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223456 tag_length_errors))
3457
3458 if tag_errors:
3459 results.append(output_api.PresubmitPromptWarning(
3460 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3461 tag_errors))
3462
dgn87d9fb62015-06-12 09:15:123463 if util_log_errors:
dgn4401aa52015-04-29 16:26:173464 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123465 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3466 util_log_errors))
3467
dgn38736db2015-09-18 19:20:513468 if tag_with_dot_errors:
3469 results.append(output_api.PresubmitPromptWarning(
3470 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3471 tag_with_dot_errors))
3472
dgn4401aa52015-04-29 16:26:173473 return results
3474
3475
Yoland Yanb92fa522017-08-28 17:37:063476def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3477 """Checks that junit.framework.* is no longer used."""
3478 deprecated_junit_framework_pattern = input_api.re.compile(
3479 r'^import junit\.framework\..*;',
3480 input_api.re.MULTILINE)
3481 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493482 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063483 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133484 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063485 for line_num, line in f.ChangedContents():
3486 if deprecated_junit_framework_pattern.search(line):
3487 errors.append("%s:%d" % (f.LocalPath(), line_num))
3488
3489 results = []
3490 if errors:
3491 results.append(output_api.PresubmitError(
3492 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3493 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3494 ' if you have any question.', errors))
3495 return results
3496
3497
3498def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3499 """Checks that if new Java test classes have inheritance.
3500 Either the new test class is JUnit3 test or it is a JUnit4 test class
3501 with a base class, either case is undesirable.
3502 """
3503 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3504
3505 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493506 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063507 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133508 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063509 if not f.OldContents():
3510 class_declaration_start_flag = False
3511 for line_num, line in f.ChangedContents():
3512 if class_declaration_pattern.search(line):
3513 class_declaration_start_flag = True
3514 if class_declaration_start_flag and ' extends ' in line:
3515 errors.append('%s:%d' % (f.LocalPath(), line_num))
3516 if '{' in line:
3517 class_declaration_start_flag = False
3518
3519 results = []
3520 if errors:
3521 results.append(output_api.PresubmitPromptWarning(
3522 'The newly created files include Test classes that inherits from base'
3523 ' class. Please do not use inheritance in JUnit4 tests or add new'
3524 ' JUnit3 tests. Contact [email protected] if you have any'
3525 ' questions.', errors))
3526 return results
3527
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203528
yolandyan45001472016-12-21 21:12:423529def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3530 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3531 deprecated_annotation_import_pattern = input_api.re.compile(
3532 r'^import android\.test\.suitebuilder\.annotation\..*;',
3533 input_api.re.MULTILINE)
3534 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493535 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423536 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133537 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423538 for line_num, line in f.ChangedContents():
3539 if deprecated_annotation_import_pattern.search(line):
3540 errors.append("%s:%d" % (f.LocalPath(), line_num))
3541
3542 results = []
3543 if errors:
3544 results.append(output_api.PresubmitError(
3545 'Annotations in android.test.suitebuilder.annotation have been'
3546 ' deprecated since API level 24. Please use android.support.test.filters'
3547 ' from //third_party/android_support_test_runner:runner_java instead.'
3548 ' Contact [email protected] if you have any questions.', errors))
3549 return results
3550
3551
agrieve7b6479d82015-10-07 14:24:223552def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3553 """Checks if MDPI assets are placed in a correct directory."""
3554 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3555 ('/res/drawable/' in f.LocalPath() or
3556 '/res/drawable-ldrtl/' in f.LocalPath()))
3557 errors = []
3558 for f in input_api.AffectedFiles(include_deletes=False,
3559 file_filter=file_filter):
3560 errors.append(' %s' % f.LocalPath())
3561
3562 results = []
3563 if errors:
3564 results.append(output_api.PresubmitError(
3565 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3566 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3567 '/res/drawable-ldrtl/.\n'
3568 'Contact [email protected] if you have questions.', errors))
3569 return results
3570
3571
Nate Fischer535972b2017-09-16 01:06:183572def _CheckAndroidWebkitImports(input_api, output_api):
3573 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353574 android.webview.ValueCallback except in the WebView glue layer
3575 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183576 """
3577 valuecallback_import_pattern = input_api.re.compile(
3578 r'^import android\.webkit\.ValueCallback;$')
3579
3580 errors = []
3581
3582 sources = lambda affected_file: input_api.FilterSourceFile(
3583 affected_file,
3584 black_list=(_EXCLUDED_PATHS +
3585 _TEST_CODE_EXCLUDED_PATHS +
3586 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353587 (r'^android_webview[\\/]glue[\\/].*',
3588 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493589 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183590
3591 for f in input_api.AffectedSourceFiles(sources):
3592 for line_num, line in f.ChangedContents():
3593 if valuecallback_import_pattern.search(line):
3594 errors.append("%s:%d" % (f.LocalPath(), line_num))
3595
3596 results = []
3597
3598 if errors:
3599 results.append(output_api.PresubmitError(
3600 'android.webkit.ValueCallback usage is detected outside of the glue'
3601 ' layer. To stay compatible with the support library, android.webkit.*'
3602 ' classes should only be used inside the glue layer and'
3603 ' org.chromium.base.Callback should be used instead.',
3604 errors))
3605
3606 return results
3607
3608
Becky Zhou7c69b50992018-12-10 19:37:573609def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3610 """Checks Android XML styles """
3611 import sys
3612 original_sys_path = sys.path
3613 try:
3614 sys.path = sys.path + [input_api.os_path.join(
3615 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3616 import checkxmlstyle
3617 finally:
3618 # Restore sys.path to what it was before.
3619 sys.path = original_sys_path
3620
3621 if is_check_on_upload:
3622 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3623 else:
3624 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3625
3626
agrievef32bcc72016-04-04 14:57:403627class PydepsChecker(object):
3628 def __init__(self, input_api, pydeps_files):
3629 self._file_cache = {}
3630 self._input_api = input_api
3631 self._pydeps_files = pydeps_files
3632
3633 def _LoadFile(self, path):
3634 """Returns the list of paths within a .pydeps file relative to //."""
3635 if path not in self._file_cache:
3636 with open(path) as f:
3637 self._file_cache[path] = f.read()
3638 return self._file_cache[path]
3639
3640 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3641 """Returns an interable of paths within the .pydep, relativized to //."""
3642 os_path = self._input_api.os_path
3643 pydeps_dir = os_path.dirname(pydeps_path)
3644 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3645 if not l.startswith('*'))
3646 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3647
3648 def _CreateFilesToPydepsMap(self):
3649 """Returns a map of local_path -> list_of_pydeps."""
3650 ret = {}
3651 for pydep_local_path in self._pydeps_files:
3652 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3653 ret.setdefault(path, []).append(pydep_local_path)
3654 return ret
3655
3656 def ComputeAffectedPydeps(self):
3657 """Returns an iterable of .pydeps files that might need regenerating."""
3658 affected_pydeps = set()
3659 file_to_pydeps_map = None
3660 for f in self._input_api.AffectedFiles(include_deletes=True):
3661 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463662 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3663 # subrepositories. We can't figure out which files change, so re-check
3664 # all files.
3665 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383666 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3667 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403668 return self._pydeps_files
3669 elif local_path.endswith('.pydeps'):
3670 if local_path in self._pydeps_files:
3671 affected_pydeps.add(local_path)
3672 elif local_path.endswith('.py'):
3673 if file_to_pydeps_map is None:
3674 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3675 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3676 return affected_pydeps
3677
3678 def DetermineIfStale(self, pydeps_path):
3679 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413680 import difflib
John Budorick47ca3fe2018-02-10 00:53:103681 import os
3682
agrievef32bcc72016-04-04 14:57:403683 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033684 if old_pydeps_data:
3685 cmd = old_pydeps_data[1][1:].strip()
3686 old_contents = old_pydeps_data[2:]
3687 else:
3688 # A default cmd that should work in most cases (as long as pydeps filename
3689 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3690 # file is empty/new.
3691 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3692 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3693 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103694 env = dict(os.environ)
3695 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403696 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103697 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413698 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033699 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413700 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403701
3702
Tibor Goldschwendt360793f72019-06-25 18:23:493703def _ParseGclientArgs():
3704 args = {}
3705 with open('build/config/gclient_args.gni', 'r') as f:
3706 for line in f:
3707 line = line.strip()
3708 if not line or line.startswith('#'):
3709 continue
3710 attribute, value = line.split('=')
3711 args[attribute.strip()] = value.strip()
3712 return args
3713
3714
agrievef32bcc72016-04-04 14:57:403715def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3716 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403717 # This check is for Python dependency lists (.pydeps files), and involves
3718 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3719 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283720 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003721 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493722 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403723 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403724 results = []
3725 # First, check for new / deleted .pydeps.
3726 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033727 # Check whether we are running the presubmit check for a file in src.
3728 # f.LocalPath is relative to repo (src, or internal repo).
3729 # os_path.exists is relative to src repo.
3730 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3731 # to src and we can conclude that the pydeps is in src.
3732 if input_api.os_path.exists(f.LocalPath()):
3733 if f.LocalPath().endswith('.pydeps'):
3734 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3735 results.append(output_api.PresubmitError(
3736 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3737 'remove %s' % f.LocalPath()))
3738 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3739 results.append(output_api.PresubmitError(
3740 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3741 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403742
3743 if results:
3744 return results
3745
Mohamed Heikal7cd4d8312020-06-16 16:49:403746 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3747 affected_pydeps = set(checker.ComputeAffectedPydeps())
3748 affected_android_pydeps = affected_pydeps.intersection(
3749 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3750 if affected_android_pydeps and not is_android:
3751 results.append(output_api.PresubmitPromptOrNotify(
3752 'You have changed python files that may affect pydeps for android\n'
3753 'specific scripts. However, the relevant presumbit check cannot be\n'
3754 'run because you are not using an Android checkout. To validate that\n'
3755 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3756 'use the android-internal-presubmit optional trybot.\n'
3757 'Possibly stale pydeps files:\n{}'.format(
3758 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403759
Mohamed Heikal7cd4d8312020-06-16 16:49:403760 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3761 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403762 try:
phajdan.jr0d9878552016-11-04 10:49:413763 result = checker.DetermineIfStale(pydep_path)
3764 if result:
3765 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403766 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413767 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3768 'To regenerate, run:\n\n %s' %
3769 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403770 except input_api.subprocess.CalledProcessError as error:
3771 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3772 long_text=error.output)]
3773
3774 return results
3775
3776
glidere61efad2015-02-18 17:39:433777def _CheckSingletonInHeaders(input_api, output_api):
3778 """Checks to make sure no header files have |Singleton<|."""
3779 def FileFilter(affected_file):
3780 # It's ok for base/memory/singleton.h to have |Singleton<|.
3781 black_list = (_EXCLUDED_PATHS +
3782 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043783 (r"^base[\\/]memory[\\/]singleton\.h$",
3784 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473785 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433786 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3787
sergeyu34d21222015-09-16 00:11:443788 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433789 files = []
3790 for f in input_api.AffectedSourceFiles(FileFilter):
3791 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3792 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3793 contents = input_api.ReadFile(f)
3794 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243795 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433796 pattern.search(line)):
3797 files.append(f)
3798 break
3799
3800 if files:
yolandyandaabc6d2016-04-18 18:29:393801 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443802 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433803 'Please move them to an appropriate source file so that the ' +
3804 'template gets instantiated in a single compilation unit.',
3805 files) ]
3806 return []
3807
3808
[email protected]fd20b902014-05-09 02:14:533809_DEPRECATED_CSS = [
3810 # Values
3811 ( "-webkit-box", "flex" ),
3812 ( "-webkit-inline-box", "inline-flex" ),
3813 ( "-webkit-flex", "flex" ),
3814 ( "-webkit-inline-flex", "inline-flex" ),
3815 ( "-webkit-min-content", "min-content" ),
3816 ( "-webkit-max-content", "max-content" ),
3817
3818 # Properties
3819 ( "-webkit-background-clip", "background-clip" ),
3820 ( "-webkit-background-origin", "background-origin" ),
3821 ( "-webkit-background-size", "background-size" ),
3822 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443823 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533824
3825 # Functions
3826 ( "-webkit-gradient", "gradient" ),
3827 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3828 ( "-webkit-linear-gradient", "linear-gradient" ),
3829 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3830 ( "-webkit-radial-gradient", "radial-gradient" ),
3831 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3832]
3833
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203834
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493835# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243836def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533837 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253838 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343839 documentation and iOS CSS for dom distiller
3840 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253841 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533842 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493843 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253844 black_list = (_EXCLUDED_PATHS +
3845 _TEST_CODE_EXCLUDED_PATHS +
3846 input_api.DEFAULT_BLACK_LIST +
3847 (r"^chrome/common/extensions/docs",
3848 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343849 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443850 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253851 r"^native_client_sdk"))
3852 file_filter = lambda f: input_api.FilterSourceFile(
3853 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533854 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3855 for line_num, line in fpath.ChangedContents():
3856 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023857 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533858 results.append(output_api.PresubmitError(
3859 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3860 (fpath.LocalPath(), line_num, deprecated_value, value)))
3861 return results
3862
mohan.reddyf21db962014-10-16 12:26:473863
rlanday6802cf632017-05-30 17:48:363864def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363865 bad_files = {}
3866 for f in input_api.AffectedFiles(include_deletes=False):
3867 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493868 not f.LocalPath().startswith('third_party/blink') and
3869 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363870 continue
3871
Daniel Bratell65b033262019-04-23 08:17:063872 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363873 continue
3874
Vaclav Brozekd5de76a2018-03-17 07:57:503875 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363876 if "#include" in line and "../" in line]
3877 if not relative_includes:
3878 continue
3879 bad_files[f.LocalPath()] = relative_includes
3880
3881 if not bad_files:
3882 return []
3883
3884 error_descriptions = []
3885 for file_path, bad_lines in bad_files.iteritems():
3886 error_description = file_path
3887 for line in bad_lines:
3888 error_description += '\n ' + line
3889 error_descriptions.append(error_description)
3890
3891 results = []
3892 results.append(output_api.PresubmitError(
3893 'You added one or more relative #include paths (including "../").\n'
3894 'These shouldn\'t be used because they can be used to include headers\n'
3895 'from code that\'s not correctly specified as a dependency in the\n'
3896 'relevant BUILD.gn file(s).',
3897 error_descriptions))
3898
3899 return results
3900
Takeshi Yoshinoe387aa32017-08-02 13:16:133901
Daniel Bratell65b033262019-04-23 08:17:063902def _CheckForCcIncludes(input_api, output_api):
3903 """Check that nobody tries to include a cc file. It's a relatively
3904 common error which results in duplicate symbols in object
3905 files. This may not always break the build until someone later gets
3906 very confusing linking errors."""
3907 results = []
3908 for f in input_api.AffectedFiles(include_deletes=False):
3909 # We let third_party code do whatever it wants
3910 if (f.LocalPath().startswith('third_party') and
3911 not f.LocalPath().startswith('third_party/blink') and
3912 not f.LocalPath().startswith('third_party\\blink')):
3913 continue
3914
3915 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3916 continue
3917
3918 for _, line in f.ChangedContents():
3919 if line.startswith('#include "'):
3920 included_file = line.split('"')[1]
3921 if _IsCPlusPlusFile(input_api, included_file):
3922 # The most common naming for external files with C++ code,
3923 # apart from standard headers, is to call them foo.inc, but
3924 # Chromium sometimes uses foo-inc.cc so allow that as well.
3925 if not included_file.endswith(('.h', '-inc.cc')):
3926 results.append(output_api.PresubmitError(
3927 'Only header files or .inc files should be included in other\n'
3928 'C++ files. Compiling the contents of a cc file more than once\n'
3929 'will cause duplicate information in the build which may later\n'
3930 'result in strange link_errors.\n' +
3931 f.LocalPath() + ':\n ' +
3932 line))
3933
3934 return results
3935
3936
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203937def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3938 if not isinstance(key, ast.Str):
3939 return 'Key at line %d must be a string literal' % key.lineno
3940 if not isinstance(value, ast.Dict):
3941 return 'Value at line %d must be a dict' % value.lineno
3942 if len(value.keys) != 1:
3943 return 'Dict at line %d must have single entry' % value.lineno
3944 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3945 return (
3946 'Entry at line %d must have a string literal \'filepath\' as key' %
3947 value.lineno)
3948 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133949
Takeshi Yoshinoe387aa32017-08-02 13:16:133950
Sergey Ulanov4af16052018-11-08 02:41:463951def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203952 if not isinstance(key, ast.Str):
3953 return 'Key at line %d must be a string literal' % key.lineno
3954 if not isinstance(value, ast.List):
3955 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463956 for element in value.elts:
3957 if not isinstance(element, ast.Str):
3958 return 'Watchlist elements on line %d is not a string' % key.lineno
3959 if not email_regex.match(element.s):
3960 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3961 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133963
Takeshi Yoshinoe387aa32017-08-02 13:16:133964
Sergey Ulanov4af16052018-11-08 02:41:463965def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203966 mismatch_template = (
3967 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3968 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133969
Sergey Ulanov4af16052018-11-08 02:41:463970 email_regex = input_api.re.compile(
3971 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3972
3973 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203974 i = 0
3975 last_key = ''
3976 while True:
3977 if i >= len(wd_dict.keys):
3978 if i >= len(w_dict.keys):
3979 return None
3980 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3981 elif i >= len(w_dict.keys):
3982 return (
3983 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203985 wd_key = wd_dict.keys[i]
3986 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133987
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203988 result = _CheckWatchlistDefinitionsEntrySyntax(
3989 wd_key, wd_dict.values[i], ast)
3990 if result is not None:
3991 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133992
Sergey Ulanov4af16052018-11-08 02:41:463993 result = _CheckWatchlistsEntrySyntax(
3994 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995 if result is not None:
3996 return 'Bad entry in WATCHLISTS dict: %s' % result
3997
3998 if wd_key.s != w_key.s:
3999 return mismatch_template % (
4000 '%s at line %d' % (wd_key.s, wd_key.lineno),
4001 '%s at line %d' % (w_key.s, w_key.lineno))
4002
4003 if wd_key.s < last_key:
4004 return (
4005 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4006 (wd_key.lineno, w_key.lineno))
4007 last_key = wd_key.s
4008
4009 i = i + 1
4010
4011
Sergey Ulanov4af16052018-11-08 02:41:464012def _CheckWATCHLISTSSyntax(expression, input_api):
4013 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204014 if not isinstance(expression, ast.Expression):
4015 return 'WATCHLISTS file must contain a valid expression'
4016 dictionary = expression.body
4017 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4018 return 'WATCHLISTS file must have single dict with exactly two entries'
4019
4020 first_key = dictionary.keys[0]
4021 first_value = dictionary.values[0]
4022 second_key = dictionary.keys[1]
4023 second_value = dictionary.values[1]
4024
4025 if (not isinstance(first_key, ast.Str) or
4026 first_key.s != 'WATCHLIST_DEFINITIONS' or
4027 not isinstance(first_value, ast.Dict)):
4028 return (
4029 'The first entry of the dict in WATCHLISTS file must be '
4030 'WATCHLIST_DEFINITIONS dict')
4031
4032 if (not isinstance(second_key, ast.Str) or
4033 second_key.s != 'WATCHLISTS' or
4034 not isinstance(second_value, ast.Dict)):
4035 return (
4036 'The second entry of the dict in WATCHLISTS file must be '
4037 'WATCHLISTS dict')
4038
Sergey Ulanov4af16052018-11-08 02:41:464039 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134040
4041
4042def _CheckWATCHLISTS(input_api, output_api):
4043 for f in input_api.AffectedFiles(include_deletes=False):
4044 if f.LocalPath() == 'WATCHLISTS':
4045 contents = input_api.ReadFile(f, 'r')
4046
4047 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204048 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134049 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204050 # Get an AST tree for it and scan the tree for detailed style checking.
4051 expression = input_api.ast.parse(
4052 contents, filename='WATCHLISTS', mode='eval')
4053 except ValueError as e:
4054 return [output_api.PresubmitError(
4055 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4056 except SyntaxError as e:
4057 return [output_api.PresubmitError(
4058 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4059 except TypeError as e:
4060 return [output_api.PresubmitError(
4061 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134062
Sergey Ulanov4af16052018-11-08 02:41:464063 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204064 if result is not None:
4065 return [output_api.PresubmitError(result)]
4066 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134067
4068 return []
4069
4070
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194071def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4072 """Checks that newly added header files have corresponding GN changes.
4073 Note that this is only a heuristic. To be precise, run script:
4074 build/check_gn_headers.py.
4075 """
4076
4077 def headers(f):
4078 return input_api.FilterSourceFile(
4079 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4080
4081 new_headers = []
4082 for f in input_api.AffectedSourceFiles(headers):
4083 if f.Action() != 'A':
4084 continue
4085 new_headers.append(f.LocalPath())
4086
4087 def gn_files(f):
4088 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4089
4090 all_gn_changed_contents = ''
4091 for f in input_api.AffectedSourceFiles(gn_files):
4092 for _, line in f.ChangedContents():
4093 all_gn_changed_contents += line
4094
4095 problems = []
4096 for header in new_headers:
4097 basename = input_api.os_path.basename(header)
4098 if basename not in all_gn_changed_contents:
4099 problems.append(header)
4100
4101 if problems:
4102 return [output_api.PresubmitPromptWarning(
4103 'Missing GN changes for new header files', items=sorted(problems),
4104 long_text='Please double check whether newly added header files need '
4105 'corresponding changes in gn or gni files.\nThis checking is only a '
4106 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4107 'Read https://crbug.com/661774 for more info.')]
4108 return []
4109
4110
Michael Giuffridad3bc8672018-10-25 22:48:024111def _CheckCorrectProductNameInMessages(input_api, output_api):
4112 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4113
4114 This assumes we won't intentionally reference one product from the other
4115 product.
4116 """
4117 all_problems = []
4118 test_cases = [{
4119 "filename_postfix": "google_chrome_strings.grd",
4120 "correct_name": "Chrome",
4121 "incorrect_name": "Chromium",
4122 }, {
4123 "filename_postfix": "chromium_strings.grd",
4124 "correct_name": "Chromium",
4125 "incorrect_name": "Chrome",
4126 }]
4127
4128 for test_case in test_cases:
4129 problems = []
4130 filename_filter = lambda x: x.LocalPath().endswith(
4131 test_case["filename_postfix"])
4132
4133 # Check each new line. Can yield false positives in multiline comments, but
4134 # easier than trying to parse the XML because messages can have nested
4135 # children, and associating message elements with affected lines is hard.
4136 for f in input_api.AffectedSourceFiles(filename_filter):
4137 for line_num, line in f.ChangedContents():
4138 if "<message" in line or "<!--" in line or "-->" in line:
4139 continue
4140 if test_case["incorrect_name"] in line:
4141 problems.append(
4142 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4143
4144 if problems:
4145 message = (
4146 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4147 % (test_case["correct_name"], test_case["correct_name"],
4148 test_case["incorrect_name"]))
4149 all_problems.append(
4150 output_api.PresubmitPromptWarning(message, items=problems))
4151
4152 return all_problems
4153
4154
Dirk Pranke3c18a382019-03-15 01:07:514155def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4156 # TODO(crbug.com/941824): We need to make sure the entries in
4157 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4158 # so that users of //buildtools in other projects get the same tooling
4159 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4160 # support to gclient, we can eliminate the duplication and delete
4161 # this presubmit check.
4162
4163 # Update this regexp if new revisions are added to the files.
4164 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264165 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514166
4167 # If a user is changing one revision, they need to change the same
4168 # line in both files. This means that any given change should contain
4169 # exactly the same list of changed lines that match the regexps. The
4170 # replace(' ', '') call allows us to ignore whitespace changes to the
4171 # lines. The 'long_text' parameter to the error will contain the
4172 # list of changed lines in both files, which should make it easy enough
4173 # to spot the error without going overboard in this implementation.
4174 revs_changes = {
4175 'DEPS': {},
4176 'buildtools/DEPS': {},
4177 }
4178 long_text = ''
4179
4180 for f in input_api.AffectedFiles(
4181 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4182 for line_num, line in f.ChangedContents():
4183 if rev_regexp.search(line):
4184 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4185 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4186
4187 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4188 return [output_api.PresubmitError(
4189 'Change buildtools revisions in sync in both //DEPS and '
4190 '//buildtools/DEPS.', long_text=long_text + '\n')]
4191 else:
4192 return []
4193
4194
Daniel Bratell93eb6c62019-04-29 20:13:364195def _CheckForTooLargeFiles(input_api, output_api):
4196 """Avoid large files, especially binary files, in the repository since
4197 git doesn't scale well for those. They will be in everyone's repo
4198 clones forever, forever making Chromium slower to clone and work
4199 with."""
4200
4201 # Uploading files to cloud storage is not trivial so we don't want
4202 # to set the limit too low, but the upper limit for "normal" large
4203 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4204 # anything over 20 MB is exceptional.
4205 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4206
4207 too_large_files = []
4208 for f in input_api.AffectedFiles():
4209 # Check both added and modified files (but not deleted files).
4210 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384211 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364212 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4213 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4214
4215 if too_large_files:
4216 message = (
4217 'Do not commit large files to git since git scales badly for those.\n' +
4218 'Instead put the large files in cloud storage and use DEPS to\n' +
4219 'fetch them.\n' + '\n'.join(too_large_files)
4220 )
4221 return [output_api.PresubmitError(
4222 'Too large files found in commit', long_text=message + '\n')]
4223 else:
4224 return []
4225
Max Morozb47503b2019-08-08 21:03:274226
4227def _CheckFuzzTargets(input_api, output_api):
4228 """Checks specific for fuzz target sources."""
4229 EXPORTED_SYMBOLS = [
4230 'LLVMFuzzerInitialize',
4231 'LLVMFuzzerCustomMutator',
4232 'LLVMFuzzerCustomCrossOver',
4233 'LLVMFuzzerMutate',
4234 ]
4235
4236 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4237
4238 def FilterFile(affected_file):
4239 """Ignore libFuzzer source code."""
4240 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4241 black_list = r"^third_party[\\/]libFuzzer"
4242
4243 return input_api.FilterSourceFile(
4244 affected_file,
4245 white_list=[white_list],
4246 black_list=[black_list])
4247
4248 files_with_missing_header = []
4249 for f in input_api.AffectedSourceFiles(FilterFile):
4250 contents = input_api.ReadFile(f, 'r')
4251 if REQUIRED_HEADER in contents:
4252 continue
4253
4254 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4255 files_with_missing_header.append(f.LocalPath())
4256
4257 if not files_with_missing_header:
4258 return []
4259
4260 long_text = (
4261 'If you define any of the libFuzzer optional functions (%s), it is '
4262 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4263 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4264 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4265 'to access command line arguments passed to the fuzzer. Instead, prefer '
4266 'static initialization and shared resources as documented in '
4267 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4268 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4269 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4270 )
4271
4272 return [output_api.PresubmitPromptWarning(
4273 message="Missing '%s' in:" % REQUIRED_HEADER,
4274 items=files_with_missing_header,
4275 long_text=long_text)]
4276
4277
Mohamed Heikald048240a2019-11-12 16:57:374278def _CheckNewImagesWarning(input_api, output_api):
4279 """
4280 Warns authors who add images into the repo to make sure their images are
4281 optimized before committing.
4282 """
4283 images_added = False
4284 image_paths = []
4285 errors = []
4286 filter_lambda = lambda x: input_api.FilterSourceFile(
4287 x,
4288 black_list=(('(?i).*test', r'.*\/junit\/')
4289 + input_api.DEFAULT_BLACK_LIST),
4290 white_list=[r'.*\/(drawable|mipmap)' ]
4291 )
4292 for f in input_api.AffectedFiles(
4293 include_deletes=False, file_filter=filter_lambda):
4294 local_path = f.LocalPath().lower()
4295 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4296 images_added = True
4297 image_paths.append(f)
4298 if images_added:
4299 errors.append(output_api.PresubmitPromptWarning(
4300 'It looks like you are trying to commit some images. If these are '
4301 'non-test-only images, please make sure to read and apply the tips in '
4302 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4303 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4304 'FYI only and will not block your CL on the CQ.', image_paths))
4305 return errors
4306
4307
dgnaa68d5e2015-06-10 10:08:224308def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574309 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224310 results = []
dgnaa68d5e2015-06-10 10:08:224311 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174312 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224313 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294314 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064315 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4316 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424317 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184318 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574319 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374320 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154321 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574322 return results
4323
4324def _AndroidSpecificOnCommitChecks(input_api, output_api):
4325 """Groups commit checks that target android code."""
4326 results = []
4327 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224328 return results
4329
Chris Hall59f8d0c72020-05-01 07:31:194330# TODO(chrishall): could we additionally match on any path owned by
4331# ui/accessibility/OWNERS ?
4332_ACCESSIBILITY_PATHS = (
4333 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4334 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4335 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4336 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4337 r"^content[\\/]browser[\\/]accessibility[\\/]",
4338 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4339 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4340 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4341 r"^ui[\\/]accessibility[\\/]",
4342 r"^ui[\\/]views[\\/]accessibility[\\/]",
4343)
4344
4345def _CheckAccessibilityRelnotesField(input_api, output_api):
4346 """Checks that commits to accessibility code contain an AX-Relnotes field in
4347 their commit message."""
4348 def FileFilter(affected_file):
4349 paths = _ACCESSIBILITY_PATHS
4350 return input_api.FilterSourceFile(affected_file, white_list=paths)
4351
4352 # Only consider changes affecting accessibility paths.
4353 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4354 return []
4355
Akihiro Ota08108e542020-05-20 15:30:534356 # AX-Relnotes can appear in either the description or the footer.
4357 # When searching the description, require 'AX-Relnotes:' to appear at the
4358 # beginning of a line.
4359 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4360 description_has_relnotes = any(ax_regex.match(line)
4361 for line in input_api.change.DescriptionText().lower().splitlines())
4362
4363 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4364 'AX-Relnotes', [])
4365 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194366 return []
4367
4368 # TODO(chrishall): link to Relnotes documentation in message.
4369 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4370 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4371 "user-facing changes"
4372 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4373 "user-facing effects"
4374 "\n if this is confusing or annoying then please contact members "
4375 "of ui/accessibility/OWNERS.")
4376
4377 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224378
[email protected]22c9bd72011-03-27 16:47:394379def _CommonChecks(input_api, output_api):
4380 """Checks common to both upload and commit."""
4381 results = []
4382 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384383 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544384 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084385
4386 author = input_api.change.author_email
4387 if author and author not in _KNOWN_ROBOTS:
4388 results.extend(
4389 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4390
Chris Hall59f8d0c72020-05-01 07:31:194391 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194392 results.extend(
[email protected]760deea2013-12-10 19:33:494393 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234394 results.extend(
4395 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544396 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184397 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344398 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524399 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224400 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444401 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594402 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314403 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064404 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124405 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184406 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224407 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304408 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494409 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034410 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494411 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444412 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294413 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274414 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074415 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544416 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444417 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394418 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554419 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044420 results.extend(
4421 input_api.canned_checks.CheckChangeHasNoTabs(
4422 input_api,
4423 output_api,
4424 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404425 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164426 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084427 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244428 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474429 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044430 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054431 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144432 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234433 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434434 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404435 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154436 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034437 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134438 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264439 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504440 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364441 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064442 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134443 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434444 results.extend(input_api.RunTests(
4445 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264446 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124447 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024448 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514449 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364450 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004451 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514452 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244453
Vaclav Brozekcdc7defb2018-03-20 09:54:354454 for f in input_api.AffectedFiles():
4455 path, name = input_api.os_path.split(f.LocalPath())
4456 if name == 'PRESUBMIT.py':
4457 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004458 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4459 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074460 # The PRESUBMIT.py file (and the directory containing it) might
4461 # have been affected by being moved or removed, so only try to
4462 # run the tests if they still exist.
4463 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4464 input_api, output_api, full_path,
4465 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394466 return results
[email protected]1f7b4172010-01-28 01:17:344467
[email protected]b337cb5b2011-01-23 21:24:054468
[email protected]b8079ae4a2012-12-05 19:56:494469def _CheckPatchFiles(input_api, output_api):
4470 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4471 if f.LocalPath().endswith(('.orig', '.rej'))]
4472 if problems:
4473 return [output_api.PresubmitError(
4474 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034475 else:
4476 return []
[email protected]b8079ae4a2012-12-05 19:56:494477
4478
Kent Tamura5a8755d2017-06-29 23:37:074479def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214480 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4481 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4482 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074483 include_re = input_api.re.compile(
4484 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4485 extension_re = input_api.re.compile(r'\.[a-z]+$')
4486 errors = []
4487 for f in input_api.AffectedFiles():
4488 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4489 continue
4490 found_line_number = None
4491 found_macro = None
4492 for line_num, line in f.ChangedContents():
4493 match = macro_re.search(line)
4494 if match:
4495 found_line_number = line_num
4496 found_macro = match.group(2)
4497 break
4498 if not found_line_number:
4499 continue
4500
4501 found_include = False
4502 for line in f.NewContents():
4503 if include_re.search(line):
4504 found_include = True
4505 break
4506 if found_include:
4507 continue
4508
4509 if not f.LocalPath().endswith('.h'):
4510 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4511 try:
4512 content = input_api.ReadFile(primary_header_path, 'r')
4513 if include_re.search(content):
4514 continue
4515 except IOError:
4516 pass
4517 errors.append('%s:%d %s macro is used without including build/'
4518 'build_config.h.'
4519 % (f.LocalPath(), found_line_number, found_macro))
4520 if errors:
4521 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4522 return []
4523
4524
[email protected]b00342e7f2013-03-26 16:21:544525def _DidYouMeanOSMacro(bad_macro):
4526 try:
4527 return {'A': 'OS_ANDROID',
4528 'B': 'OS_BSD',
4529 'C': 'OS_CHROMEOS',
4530 'F': 'OS_FREEBSD',
4531 'L': 'OS_LINUX',
4532 'M': 'OS_MACOSX',
4533 'N': 'OS_NACL',
4534 'O': 'OS_OPENBSD',
4535 'P': 'OS_POSIX',
4536 'S': 'OS_SOLARIS',
4537 'W': 'OS_WIN'}[bad_macro[3].upper()]
4538 except KeyError:
4539 return ''
4540
4541
4542def _CheckForInvalidOSMacrosInFile(input_api, f):
4543 """Check for sensible looking, totally invalid OS macros."""
4544 preprocessor_statement = input_api.re.compile(r'^\s*#')
4545 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4546 results = []
4547 for lnum, line in f.ChangedContents():
4548 if preprocessor_statement.search(line):
4549 for match in os_macro.finditer(line):
4550 if not match.group(1) in _VALID_OS_MACROS:
4551 good = _DidYouMeanOSMacro(match.group(1))
4552 did_you_mean = ' (did you mean %s?)' % good if good else ''
4553 results.append(' %s:%d %s%s' % (f.LocalPath(),
4554 lnum,
4555 match.group(1),
4556 did_you_mean))
4557 return results
4558
4559
4560def _CheckForInvalidOSMacros(input_api, output_api):
4561 """Check all affected files for invalid OS macros."""
4562 bad_macros = []
tzik3f295992018-12-04 20:32:234563 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474564 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544565 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4566
4567 if not bad_macros:
4568 return []
4569
4570 return [output_api.PresubmitError(
4571 'Possibly invalid OS macro[s] found. Please fix your code\n'
4572 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4573
lliabraa35bab3932014-10-01 12:16:444574
4575def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4576 """Check all affected files for invalid "if defined" macros."""
4577 ALWAYS_DEFINED_MACROS = (
4578 "TARGET_CPU_PPC",
4579 "TARGET_CPU_PPC64",
4580 "TARGET_CPU_68K",
4581 "TARGET_CPU_X86",
4582 "TARGET_CPU_ARM",
4583 "TARGET_CPU_MIPS",
4584 "TARGET_CPU_SPARC",
4585 "TARGET_CPU_ALPHA",
4586 "TARGET_IPHONE_SIMULATOR",
4587 "TARGET_OS_EMBEDDED",
4588 "TARGET_OS_IPHONE",
4589 "TARGET_OS_MAC",
4590 "TARGET_OS_UNIX",
4591 "TARGET_OS_WIN32",
4592 )
4593 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4594 results = []
4595 for lnum, line in f.ChangedContents():
4596 for match in ifdef_macro.finditer(line):
4597 if match.group(1) in ALWAYS_DEFINED_MACROS:
4598 always_defined = ' %s is always defined. ' % match.group(1)
4599 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4600 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4601 lnum,
4602 always_defined,
4603 did_you_mean))
4604 return results
4605
4606
4607def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4608 """Check all affected files for invalid "if defined" macros."""
4609 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054610 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444611 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054612 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214613 continue
lliabraa35bab3932014-10-01 12:16:444614 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4615 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4616
4617 if not bad_macros:
4618 return []
4619
4620 return [output_api.PresubmitError(
4621 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4622 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4623 bad_macros)]
4624
4625
mlamouria82272622014-09-16 18:45:044626def _CheckForIPCRules(input_api, output_api):
4627 """Check for same IPC rules described in
4628 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4629 """
4630 base_pattern = r'IPC_ENUM_TRAITS\('
4631 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4632 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4633
4634 problems = []
4635 for f in input_api.AffectedSourceFiles(None):
4636 local_path = f.LocalPath()
4637 if not local_path.endswith('.h'):
4638 continue
4639 for line_number, line in f.ChangedContents():
4640 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4641 problems.append(
4642 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4643
4644 if problems:
4645 return [output_api.PresubmitPromptWarning(
4646 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4647 else:
4648 return []
4649
[email protected]b00342e7f2013-03-26 16:21:544650
Stephen Martinis97a394142018-06-07 23:06:054651def _CheckForLongPathnames(input_api, output_api):
4652 """Check to make sure no files being submitted have long paths.
4653 This causes issues on Windows.
4654 """
4655 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194656 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054657 local_path = f.LocalPath()
4658 # Windows has a path limit of 260 characters. Limit path length to 200 so
4659 # that we have some extra for the prefix on dev machines and the bots.
4660 if len(local_path) > 200:
4661 problems.append(local_path)
4662
4663 if problems:
4664 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4665 else:
4666 return []
4667
4668
Daniel Bratell8ba52722018-03-02 16:06:144669def _CheckForIncludeGuards(input_api, output_api):
4670 """Check that header files have proper guards against multiple inclusion.
4671 If a file should not have such guards (and it probably should) then it
4672 should include the string "no-include-guard-because-multiply-included".
4673 """
Daniel Bratell6a75baef62018-06-04 10:04:454674 def is_chromium_header_file(f):
4675 # We only check header files under the control of the Chromium
4676 # project. That is, those outside third_party apart from
4677 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324678 # We also exclude *_message_generator.h headers as they use
4679 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454680 file_with_path = input_api.os_path.normpath(f.LocalPath())
4681 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324682 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454683 (not file_with_path.startswith('third_party') or
4684 file_with_path.startswith(
4685 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144686
4687 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344688 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144689
4690 errors = []
4691
Daniel Bratell6a75baef62018-06-04 10:04:454692 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144693 guard_name = None
4694 guard_line_number = None
4695 seen_guard_end = False
4696
4697 file_with_path = input_api.os_path.normpath(f.LocalPath())
4698 base_file_name = input_api.os_path.splitext(
4699 input_api.os_path.basename(file_with_path))[0]
4700 upper_base_file_name = base_file_name.upper()
4701
4702 expected_guard = replace_special_with_underscore(
4703 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144704
4705 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574706 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4707 # are too many (1000+) files with slight deviations from the
4708 # coding style. The most important part is that the include guard
4709 # is there, and that it's unique, not the name so this check is
4710 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144711 #
4712 # As code becomes more uniform, this could be made stricter.
4713
4714 guard_name_pattern_list = [
4715 # Anything with the right suffix (maybe with an extra _).
4716 r'\w+_H__?',
4717
Daniel Bratell39b5b062018-05-16 18:09:574718 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144719 r'\w+_h',
4720
4721 # Anything including the uppercase name of the file.
4722 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4723 upper_base_file_name)) + r'\w*',
4724 ]
4725 guard_name_pattern = '|'.join(guard_name_pattern_list)
4726 guard_pattern = input_api.re.compile(
4727 r'#ifndef\s+(' + guard_name_pattern + ')')
4728
4729 for line_number, line in enumerate(f.NewContents()):
4730 if 'no-include-guard-because-multiply-included' in line:
4731 guard_name = 'DUMMY' # To not trigger check outside the loop.
4732 break
4733
4734 if guard_name is None:
4735 match = guard_pattern.match(line)
4736 if match:
4737 guard_name = match.group(1)
4738 guard_line_number = line_number
4739
Daniel Bratell39b5b062018-05-16 18:09:574740 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454741 # don't match the chromium style guide, but new files should
4742 # get it right.
4743 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574744 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144745 errors.append(output_api.PresubmitPromptWarning(
4746 'Header using the wrong include guard name %s' % guard_name,
4747 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574748 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144749 else:
4750 # The line after #ifndef should have a #define of the same name.
4751 if line_number == guard_line_number + 1:
4752 expected_line = '#define %s' % guard_name
4753 if line != expected_line:
4754 errors.append(output_api.PresubmitPromptWarning(
4755 'Missing "%s" for include guard' % expected_line,
4756 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4757 'Expected: %r\nGot: %r' % (expected_line, line)))
4758
4759 if not seen_guard_end and line == '#endif // %s' % guard_name:
4760 seen_guard_end = True
4761 elif seen_guard_end:
4762 if line.strip() != '':
4763 errors.append(output_api.PresubmitPromptWarning(
4764 'Include guard %s not covering the whole file' % (
4765 guard_name), [f.LocalPath()]))
4766 break # Nothing else to check and enough to warn once.
4767
4768 if guard_name is None:
4769 errors.append(output_api.PresubmitPromptWarning(
4770 'Missing include guard %s' % expected_guard,
4771 [f.LocalPath()],
4772 'Missing include guard in %s\n'
4773 'Recommended name: %s\n'
4774 'This check can be disabled by having the string\n'
4775 'no-include-guard-because-multiply-included in the header.' %
4776 (f.LocalPath(), expected_guard)))
4777
4778 return errors
4779
4780
mostynbb639aca52015-01-07 20:31:234781def _CheckForWindowsLineEndings(input_api, output_api):
4782 """Check source code and known ascii text files for Windows style line
4783 endings.
4784 """
earthdok1b5e0ee2015-03-10 15:19:104785 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234786
4787 file_inclusion_pattern = (
4788 known_text_files,
4789 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4790 )
4791
mostynbb639aca52015-01-07 20:31:234792 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534793 source_file_filter = lambda f: input_api.FilterSourceFile(
4794 f, white_list=file_inclusion_pattern, black_list=None)
4795 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504796 include_file = False
4797 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234798 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504799 include_file = True
4800 if include_file:
4801 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234802
4803 if problems:
4804 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4805 'these files to contain Windows style line endings?\n' +
4806 '\n'.join(problems))]
4807
4808 return []
4809
4810
Vaclav Brozekd5de76a2018-03-17 07:57:504811def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134812 """Checks that all source files use SYSLOG properly."""
4813 syslog_files = []
4814 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564815 for line_number, line in f.ChangedContents():
4816 if 'SYSLOG' in line:
4817 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4818
pastarmovj89f7ee12016-09-20 14:58:134819 if syslog_files:
4820 return [output_api.PresubmitPromptWarning(
4821 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4822 ' calls.\nFiles to check:\n', items=syslog_files)]
4823 return []
4824
4825
[email protected]1f7b4172010-01-28 01:17:344826def CheckChangeOnUpload(input_api, output_api):
4827 results = []
4828 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474829 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284830 results.extend(
jam93a6ee792017-02-08 23:59:224831 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194832 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224833 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134834 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164835 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534836 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194837 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274838 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544839 return results
[email protected]ca8d1982009-02-19 16:33:124840
4841
[email protected]1bfb8322014-04-23 01:02:414842def GetTryServerMasterForBot(bot):
4843 """Returns the Try Server master for the given bot.
4844
[email protected]0bb112362014-07-26 04:38:324845 It tries to guess the master from the bot name, but may still fail
4846 and return None. There is no longer a default master.
4847 """
4848 # Potentially ambiguous bot names are listed explicitly.
4849 master_map = {
tandriie5587792016-07-14 00:34:504850 'chromium_presubmit': 'master.tryserver.chromium.linux',
4851 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414852 }
[email protected]0bb112362014-07-26 04:38:324853 master = master_map.get(bot)
4854 if not master:
wnwen4fbaab82016-05-25 12:54:364855 if 'android' in bot:
tandriie5587792016-07-14 00:34:504856 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364857 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504858 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324859 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504860 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324861 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504862 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324863 return master
[email protected]1bfb8322014-04-23 01:02:414864
4865
[email protected]ca8d1982009-02-19 16:33:124866def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544867 results = []
[email protected]1f7b4172010-01-28 01:17:344868 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574869 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544870 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274871 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344872 input_api,
4873 output_api,
[email protected]2fdd1f362013-01-16 03:56:034874 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274875
jam93a6ee792017-02-08 23:59:224876 results.extend(
4877 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544878 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4879 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384880 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4881 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414882 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4883 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544884 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144885
4886
Rainhard Findlingfc31844c52020-05-15 09:58:264887def _CheckStrings(input_api, output_api):
4888 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024889 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4890 # footer is set to true.
4891 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264892 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024893 footer.lower()
4894 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264895 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024896
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144897 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264898 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144899 import sys
4900 from io import StringIO
4901
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144902 new_or_added_paths = set(f.LocalPath()
4903 for f in input_api.AffectedFiles()
4904 if (f.Action() == 'A' or f.Action() == 'M'))
4905 removed_paths = set(f.LocalPath()
4906 for f in input_api.AffectedFiles(include_deletes=True)
4907 if f.Action() == 'D')
4908
4909 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264910 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164911 if not affected_grds:
4912 return []
4913
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144914 affected_png_paths = [f.AbsoluteLocalPath()
4915 for f in input_api.AffectedFiles()
4916 if (f.LocalPath().endswith('.png'))]
4917
4918 # Check for screenshots. Developers can upload screenshots using
4919 # tools/translation/upload_screenshots.py which finds and uploads
4920 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4921 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4922 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4923 #
4924 # The logic here is as follows:
4925 #
4926 # - If the CL has a .png file under the screenshots directory for a grd
4927 # file, warn the developer. Actual images should never be checked into the
4928 # Chrome repo.
4929 #
4930 # - If the CL contains modified or new messages in grd files and doesn't
4931 # contain the corresponding .sha1 files, warn the developer to add images
4932 # and upload them via tools/translation/upload_screenshots.py.
4933 #
4934 # - If the CL contains modified or new messages in grd files and the
4935 # corresponding .sha1 files, everything looks good.
4936 #
4937 # - If the CL contains removed messages in grd files but the corresponding
4938 # .sha1 files aren't removed, warn the developer to remove them.
4939 unnecessary_screenshots = []
4940 missing_sha1 = []
4941 unnecessary_sha1_files = []
4942
Rainhard Findlingfc31844c52020-05-15 09:58:264943 # This checks verifies that the ICU syntax of messages this CL touched is
4944 # valid, and reports any found syntax errors.
4945 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4946 # without developers being aware of them. Later on, such ICU syntax errors
4947 # break message extraction for translation, hence would block Chromium
4948 # translations until they are fixed.
4949 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144950
4951 def _CheckScreenshotAdded(screenshots_dir, message_id):
4952 sha1_path = input_api.os_path.join(
4953 screenshots_dir, message_id + '.png.sha1')
4954 if sha1_path not in new_or_added_paths:
4955 missing_sha1.append(sha1_path)
4956
4957
4958 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4959 sha1_path = input_api.os_path.join(
4960 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034961 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144962 unnecessary_sha1_files.append(sha1_path)
4963
Rainhard Findlingfc31844c52020-05-15 09:58:264964
4965 def _ValidateIcuSyntax(text, level, signatures):
4966 """Validates ICU syntax of a text string.
4967
4968 Check if text looks similar to ICU and checks for ICU syntax correctness
4969 in this case. Reports various issues with ICU syntax and values of
4970 variants. Supports checking of nested messages. Accumulate information of
4971 each ICU messages found in the text for further checking.
4972
4973 Args:
4974 text: a string to check.
4975 level: a number of current nesting level.
4976 signatures: an accumulator, a list of tuple of (level, variable,
4977 kind, variants).
4978
4979 Returns:
4980 None if a string is not ICU or no issue detected.
4981 A tuple of (message, start index, end index) if an issue detected.
4982 """
4983 valid_types = {
4984 'plural': (frozenset(
4985 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4986 frozenset(['=1', 'other'])),
4987 'selectordinal': (frozenset(
4988 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4989 frozenset(['one', 'other'])),
4990 'select': (frozenset(), frozenset(['other'])),
4991 }
4992
4993 # Check if the message looks like an attempt to use ICU
4994 # plural. If yes - check if its syntax strictly matches ICU format.
4995 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4996 if not like:
4997 signatures.append((level, None, None, None))
4998 return
4999
5000 # Check for valid prefix and suffix
5001 m = re.match(
5002 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5003 r'(plural|selectordinal|select),\s*'
5004 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5005 if not m:
5006 return (('This message looks like an ICU plural, '
5007 'but does not follow ICU syntax.'), like.start(), like.end())
5008 starting, variable, kind, variant_pairs = m.groups()
5009 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5010 if depth:
5011 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5012 len(text))
5013 first = text[0]
5014 ending = text[last_pos:]
5015 if not starting:
5016 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5017 last_pos)
5018 if not ending or '}' not in ending:
5019 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5020 last_pos)
5021 elif first != '{':
5022 return (
5023 ('Invalid ICU format. Extra characters at the start of a complex '
5024 'message (go/icu-message-migration): "%s"') %
5025 starting, 0, len(starting))
5026 elif ending != '}':
5027 return (('Invalid ICU format. Extra characters at the end of a complex '
5028 'message (go/icu-message-migration): "%s"')
5029 % ending, last_pos - 1, len(text) - 1)
5030 if kind not in valid_types:
5031 return (('Unknown ICU message type %s. '
5032 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5033 known, required = valid_types[kind]
5034 defined_variants = set()
5035 for variant, variant_range, value, value_range in variants:
5036 start, end = variant_range
5037 if variant in defined_variants:
5038 return ('Variant "%s" is defined more than once' % variant,
5039 start, end)
5040 elif known and variant not in known:
5041 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5042 start, end)
5043 defined_variants.add(variant)
5044 # Check for nested structure
5045 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5046 if res:
5047 return (res[0], res[1] + value_range[0] + 1,
5048 res[2] + value_range[0] + 1)
5049 missing = required - defined_variants
5050 if missing:
5051 return ('Required variants missing: %s' % ', '.join(missing), 0,
5052 len(text))
5053 signatures.append((level, variable, kind, defined_variants))
5054
5055
5056 def _ParseIcuVariants(text, offset=0):
5057 """Parse variants part of ICU complex message.
5058
5059 Builds a tuple of variant names and values, as well as
5060 their offsets in the input string.
5061
5062 Args:
5063 text: a string to parse
5064 offset: additional offset to add to positions in the text to get correct
5065 position in the complete ICU string.
5066
5067 Returns:
5068 List of tuples, each tuple consist of four fields: variant name,
5069 variant name span (tuple of two integers), variant value, value
5070 span (tuple of two integers).
5071 """
5072 depth, start, end = 0, -1, -1
5073 variants = []
5074 key = None
5075 for idx, char in enumerate(text):
5076 if char == '{':
5077 if not depth:
5078 start = idx
5079 chunk = text[end + 1:start]
5080 key = chunk.strip()
5081 pos = offset + end + 1 + chunk.find(key)
5082 span = (pos, pos + len(key))
5083 depth += 1
5084 elif char == '}':
5085 if not depth:
5086 return variants, depth, offset + idx
5087 depth -= 1
5088 if not depth:
5089 end = idx
5090 variants.append((key, span, text[start:end + 1], (offset + start,
5091 offset + end + 1)))
5092 return variants, depth, offset + end + 1
5093
meacer8c0d3832019-12-26 21:46:165094 try:
5095 old_sys_path = sys.path
5096 sys.path = sys.path + [input_api.os_path.join(
5097 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5098 from helper import grd_helper
5099 finally:
5100 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145101
5102 for f in affected_grds:
5103 file_path = f.LocalPath()
5104 old_id_to_msg_map = {}
5105 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385106 # Note that this code doesn't check if the file has been deleted. This is
5107 # OK because it only uses the old and new file contents and doesn't load
5108 # the file via its path.
5109 # It's also possible that a file's content refers to a renamed or deleted
5110 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5111 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5112 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145113 if file_path.endswith('.grdp'):
5114 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585115 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395116 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585118 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395119 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145120 else:
meacerff8a9b62019-12-10 19:43:585121 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585123 old_id_to_msg_map = grd_helper.GetGrdMessages(
5124 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145125 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585126 new_id_to_msg_map = grd_helper.GetGrdMessages(
5127 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145128
5129 # Compute added, removed and modified message IDs.
5130 old_ids = set(old_id_to_msg_map)
5131 new_ids = set(new_id_to_msg_map)
5132 added_ids = new_ids - old_ids
5133 removed_ids = old_ids - new_ids
5134 modified_ids = set([])
5135 for key in old_ids.intersection(new_ids):
5136 if (old_id_to_msg_map[key].FormatXml()
5137 != new_id_to_msg_map[key].FormatXml()):
5138 modified_ids.add(key)
5139
5140 grd_name, ext = input_api.os_path.splitext(
5141 input_api.os_path.basename(file_path))
5142 screenshots_dir = input_api.os_path.join(
5143 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5144
Rainhard Findlingfc31844c52020-05-15 09:58:265145 if run_screenshot_check:
5146 # Check the screenshot directory for .png files. Warn if there is any.
5147 for png_path in affected_png_paths:
5148 if png_path.startswith(screenshots_dir):
5149 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145150
Rainhard Findlingfc31844c52020-05-15 09:58:265151 for added_id in added_ids:
5152 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145153
Rainhard Findlingfc31844c52020-05-15 09:58:265154 for modified_id in modified_ids:
5155 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
Rainhard Findlingfc31844c52020-05-15 09:58:265157 for removed_id in removed_ids:
5158 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5159
5160 # Check new and changed strings for ICU syntax errors.
5161 for key in added_ids.union(modified_ids):
5162 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5163 err = _ValidateIcuSyntax(msg, 0, [])
5164 if err is not None:
5165 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145166
5167 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265168 if run_screenshot_check:
5169 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005170 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265171 'Do not include actual screenshots in the changelist. Run '
5172 'tools/translate/upload_screenshots.py to upload them instead:',
5173 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145174
Rainhard Findlingfc31844c52020-05-15 09:58:265175 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005176 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265177 'You are adding or modifying UI strings.\n'
5178 'To ensure the best translations, take screenshots of the relevant UI '
5179 '(https://g.co/chrome/translation) and add these files to your '
5180 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145181
Rainhard Findlingfc31844c52020-05-15 09:58:265182 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005183 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265184 'You removed strings associated with these files. Remove:',
5185 sorted(unnecessary_sha1_files)))
5186 else:
5187 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5188 'screenshots check.'))
5189
5190 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075191 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265192 'ICU syntax errors were found in the following strings (problems or '
5193 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145194
5195 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125196
5197
5198def _CheckTranslationExpectations(input_api, output_api,
5199 repo_root=None,
5200 translation_expectations_path=None,
5201 grd_files=None):
5202 import sys
5203 affected_grds = [f for f in input_api.AffectedFiles()
5204 if (f.LocalPath().endswith('.grd') or
5205 f.LocalPath().endswith('.grdp'))]
5206 if not affected_grds:
5207 return []
5208
5209 try:
5210 old_sys_path = sys.path
5211 sys.path = sys.path + [
5212 input_api.os_path.join(
5213 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5214 from helper import git_helper
5215 from helper import translation_helper
5216 finally:
5217 sys.path = old_sys_path
5218
5219 # Check that translation expectations can be parsed and we can get a list of
5220 # translatable grd files. |repo_root| and |translation_expectations_path| are
5221 # only passed by tests.
5222 if not repo_root:
5223 repo_root = input_api.PresubmitLocalPath()
5224 if not translation_expectations_path:
5225 translation_expectations_path = input_api.os_path.join(
5226 repo_root, 'tools', 'gritsettings',
5227 'translation_expectations.pyl')
5228 if not grd_files:
5229 grd_files = git_helper.list_grds_in_repository(repo_root)
5230
5231 try:
5232 translation_helper.get_translatable_grds(repo_root, grd_files,
5233 translation_expectations_path)
5234 except Exception as e:
5235 return [output_api.PresubmitNotifyResult(
5236 'Failed to get a list of translatable grd files. This happens when:\n'
5237 ' - One of the modified grd or grdp files cannot be parsed or\n'
5238 ' - %s is not updated.\n'
5239 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5240 return []
Ken Rockotc31f4832020-05-29 18:58:515241
5242
5243def _CheckStableMojomChanges(input_api, output_api):
5244 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095245 changed_mojoms = input_api.AffectedFiles(
5246 include_deletes=True,
5247 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515248 delta = []
5249 for mojom in changed_mojoms:
5250 old_contents = ''.join(mojom.OldContents()) or None
5251 new_contents = ''.join(mojom.NewContents()) or None
5252 delta.append({
5253 'filename': mojom.LocalPath(),
5254 'old': '\n'.join(mojom.OldContents()) or None,
5255 'new': '\n'.join(mojom.NewContents()) or None,
5256 })
5257
5258 process = input_api.subprocess.Popen(
5259 [input_api.python_executable,
5260 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5261 'public', 'tools', 'mojom',
5262 'check_stable_mojom_compatibility.py'),
5263 '--src-root', input_api.PresubmitLocalPath()],
5264 stdin=input_api.subprocess.PIPE,
5265 stdout=input_api.subprocess.PIPE,
5266 stderr=input_api.subprocess.PIPE,
5267 universal_newlines=True)
5268 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5269 if process.returncode:
5270 return [output_api.PresubmitError(
5271 'One or more [Stable] mojom definitions appears to have been changed '
5272 'in a way that is not backward-compatible.',
5273 long_text=error)]
5274 return []