blob: 30bc0f70216918c070fcb51f6d8657e6e9d8ef91 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1429 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5431 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0432 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4033)
[email protected]ca8d1982009-02-19 16:33:1234
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Fragment of a regular expression that matches C++ and Objective-C++
37# implementation files.
38_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
39
wnwenbdc444e2016-05-25 13:44:1540
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1941# Fragment of a regular expression that matches C++ and Objective-C++
42# header files.
43_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
44
45
[email protected]06e6d0ff2012-12-11 01:36:4446# Regular expression that matches code only used for test binaries
47# (best effort).
48_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0449 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4450 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4451 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1252 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1853 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4454 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0455 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0556 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0457 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4758 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0459 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0860 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0461 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4162 # EarlGrey app side code for tests.
63 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1764 # Views Examples code
65 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4466)
[email protected]ca8d1982009-02-19 16:33:1267
Daniel Bratell609102be2019-03-27 20:53:2168_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1569
[email protected]eea609a2011-11-18 13:10:1270_TEST_ONLY_WARNING = (
71 'You might be calling functions intended only for testing from\n'
72 'production code. It is OK to ignore this warning if you know what\n'
73 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0774 'not perfect. The commit queue will not block on this warning,\n'
75 'however the android-binary-size trybot will block if the method\n'
76 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1277
78
[email protected]cf9b78f2012-11-14 11:40:2879_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4080 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2181 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
82 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2883
Michael Thiessen44457642020-02-06 00:24:1584# Format: Sequence of tuples containing:
85# * Full import path.
86# * Sequence of strings to show when the pattern matches.
87# * Sequence of path or filename exceptions to this rule
88_BANNED_JAVA_IMPORTS = (
89 (
Colin Blundell170d78c82020-03-12 13:56:0490 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1591 (
92 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
93 ),
94 (
95 'net/android/javatests/src/org/chromium/net/'
96 'AndroidProxySelectorTest.java',
97 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:0498 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:1599 ),
100 ),
101)
wnwenbdc444e2016-05-25 13:44:15102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41107_BANNED_JAVA_FUNCTIONS = (
108 (
109 'StrictMode.allowThreadDiskReads()',
110 (
111 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
112 'directly.',
113 ),
114 False,
115 ),
116 (
117 'StrictMode.allowThreadDiskWrites()',
118 (
119 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
120 'directly.',
121 ),
122 False,
123 ),
124)
125
Daniel Bratell609102be2019-03-27 20:53:21126# Format: Sequence of tuples containing:
127# * String pattern or, if starting with a slash, a regular expression.
128# * Sequence of strings to show when the pattern matches.
129# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59130_BANNED_OBJC_FUNCTIONS = (
131 (
132 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59135 'prohibited. Please use CrTrackingArea instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 False,
139 ),
140 (
[email protected]eaae1972014-04-16 04:17:26141 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59144 'instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 False,
148 ),
149 (
150 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertPoint:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertPoint:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
167 (
168 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20169 (
170 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59171 'Please use |convertRect:(point) fromView:nil| instead.',
172 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
173 ),
174 True,
175 ),
176 (
177 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20178 (
179 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59180 'Please use |convertRect:(point) toView:nil| instead.',
181 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
182 ),
183 True,
184 ),
185 (
186 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20187 (
188 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59189 'Please use |convertSize:(point) fromView:nil| instead.',
190 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
191 ),
192 True,
193 ),
194 (
195 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20196 (
197 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59198 'Please use |convertSize:(point) toView:nil| instead.',
199 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
200 ),
201 True,
202 ),
jif65398702016-10-27 10:19:48203 (
204 r"/\s+UTF8String\s*]",
205 (
206 'The use of -[NSString UTF8String] is dangerous as it can return null',
207 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
208 'Please use |SysNSStringToUTF8| instead.',
209 ),
210 True,
211 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34212 (
213 r'__unsafe_unretained',
214 (
215 'The use of __unsafe_unretained is almost certainly wrong, unless',
216 'when interacting with NSFastEnumeration or NSInvocation.',
217 'Please use __weak in files build with ARC, nothing otherwise.',
218 ),
219 False,
220 ),
Avi Drissman7382afa02019-04-29 23:27:13221 (
222 'freeWhenDone:NO',
223 (
224 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
225 'Foundation types is prohibited.',
226 ),
227 True,
228 ),
[email protected]127f18ec2012-06-16 05:05:59229)
230
Daniel Bratell609102be2019-03-27 20:53:21231# Format: Sequence of tuples containing:
232# * String pattern or, if starting with a slash, a regular expression.
233# * Sequence of strings to show when the pattern matches.
234# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54235_BANNED_IOS_OBJC_FUNCTIONS = (
236 (
237 r'/\bTEST[(]',
238 (
239 'TEST() macro should not be used in Objective-C++ code as it does not ',
240 'drain the autorelease pool at the end of the test. Use TEST_F() ',
241 'macro instead with a fixture inheriting from PlatformTest (or a ',
242 'typedef).'
243 ),
244 True,
245 ),
246 (
247 r'/\btesting::Test\b',
248 (
249 'testing::Test should not be used in Objective-C++ code as it does ',
250 'not drain the autorelease pool at the end of the test. Use ',
251 'PlatformTest instead.'
252 ),
253 True,
254 ),
255)
256
Peter K. Lee6c03ccff2019-07-15 14:40:05257# Format: Sequence of tuples containing:
258# * String pattern or, if starting with a slash, a regular expression.
259# * Sequence of strings to show when the pattern matches.
260# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
261_BANNED_IOS_EGTEST_FUNCTIONS = (
262 (
263 r'/\bEXPECT_OCMOCK_VERIFY\b',
264 (
265 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
266 'it is meant for GTests. Use [mock verify] instead.'
267 ),
268 True,
269 ),
270)
271
danakj7a2b7082019-05-21 21:13:51272# Directories that contain deprecated Bind() or Callback types.
273# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36274# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51275# echo "-- $i"
danakj710b4c02019-11-28 16:08:45276# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51277# done
278#
279# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
280# when they have been converted to modern callback types (OnceCallback,
281# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
282# checks for them and prevent regressions.
283_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51284 '^apps/',
danakj7a2b7082019-05-21 21:13:51285 '^base/callback.h', # Intentional.
286 '^chrome/app/',
287 '^chrome/browser/',
288 '^chrome/chrome_elf/',
danakj7a2b7082019-05-21 21:13:51289 '^chrome/common/',
290 '^chrome/installer/',
danakj7a2b7082019-05-21 21:13:51291 '^chrome/renderer/',
292 '^chrome/services/',
293 '^chrome/test/',
294 '^chrome/tools/',
295 '^chrome/utility/',
danakj7a2b7082019-05-21 21:13:51296 '^chromecast/media/',
297 '^chromecast/metrics/',
298 '^chromecast/net/',
299 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51300 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51301 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51302 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51303 '^components/arc/',
304 '^components/assist_ranker/',
305 '^components/autofill/',
306 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51307 '^components/browser_watcher/',
danakj7a2b7082019-05-21 21:13:51308 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51309 '^components/chromeos_camera/',
310 '^components/component_updater/',
311 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51312 '^components/cronet/',
313 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51314 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36315 '^components/dom_distiller/',
Joey Scarr164d7072020-04-21 03:13:39316 '^components/download/internal/common/',
danakj7a2b7082019-05-21 21:13:51317 '^components/drive/',
318 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51323 '^components/guest_view/',
324 '^components/heap_profiling/',
325 '^components/history/',
326 '^components/image_fetcher/',
327 '^components/invalidation/',
328 '^components/keyed_service/',
329 '^components/login/',
330 '^components/metrics/',
331 '^components/metrics_services_manager/',
332 '^components/nacl/',
333 '^components/navigation_interception/',
334 '^components/net_log/',
335 '^components/network_time/',
336 '^components/ntp_snippets/',
337 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51338 '^components/offline_pages/',
339 '^components/omnibox/',
340 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51341 '^components/password_manager/',
342 '^components/payments/',
343 '^components/plugins/',
344 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51345 '^components/proxy_config/',
346 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51347 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51348 '^components/rlz/',
349 '^components/safe_browsing/',
350 '^components/search_engines/',
351 '^components/search_provider_logos/',
352 '^components/security_interstitials/',
353 '^components/security_state/',
354 '^components/services/',
355 '^components/sessions/',
356 '^components/signin/',
357 '^components/ssl_errors/',
358 '^components/storage_monitor/',
359 '^components/subresource_filter/',
360 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51361 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51362 '^components/sync_preferences/',
363 '^components/sync_sessions/',
364 '^components/test/',
365 '^components/tracing/',
366 '^components/translate/',
367 '^components/ukm/',
368 '^components/update_client/',
369 '^components/upload_list/',
370 '^components/variations/',
371 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51372 '^components/webcrypto/',
373 '^components/webdata/',
374 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51375 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20376 '^extensions/browser/',
377 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51378 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51379 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51380 '^ios/chrome/',
381 '^ios/components/',
382 '^ios/net/',
383 '^ios/web/',
384 '^ios/web_view/',
385 '^ipc/',
danakj7a2b7082019-05-21 21:13:51386 '^media/base/',
danakjc8576092019-11-26 19:01:36387 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51388 '^media/cast/',
389 '^media/cdm/',
390 '^media/device_monitors/',
danakj7a2b7082019-05-21 21:13:51391 '^media/filters/',
392 '^media/formats/',
393 '^media/gpu/',
394 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51395 '^media/renderers/',
danakj7a2b7082019-05-21 21:13:51396 '^net/',
397 '^ppapi/proxy/',
398 '^ppapi/shared_impl/',
399 '^ppapi/tests/',
400 '^ppapi/thunk/',
401 '^remoting/base/',
402 '^remoting/client/',
danakj7a2b7082019-05-21 21:13:51403 '^remoting/host/',
404 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51405 '^remoting/protocol/',
danakj7a2b7082019-05-21 21:13:51406 '^services/',
danakj7a2b7082019-05-21 21:13:51407 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51408 '^tools/clang/base_bind_rewriters/', # Intentional.
409 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51410))
[email protected]127f18ec2012-06-16 05:05:59411
Daniel Bratell609102be2019-03-27 20:53:21412# Format: Sequence of tuples containing:
413# * String pattern or, if starting with a slash, a regular expression.
414# * Sequence of strings to show when the pattern matches.
415# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
416# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59417_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20418 (
Dave Tapuska98199b612019-07-10 13:30:44419 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53420 (
421 'New code should not use NULL. Use nullptr instead.',
422 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20423 False,
thomasandersone7caaa9b2017-03-29 19:22:53424 (),
425 ),
Peter Kasting94a56c42019-10-25 21:54:04426 (
427 r'/\busing namespace ',
428 (
429 'Using directives ("using namespace x") are banned by the Google Style',
430 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
431 'Explicitly qualify symbols or use using declarations ("using x::foo").',
432 ),
433 True,
434 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
435 ),
Antonio Gomes07300d02019-03-13 20:59:57436 # Make sure that gtest's FRIEND_TEST() macro is not used; the
437 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
438 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53439 (
[email protected]23e6cbc2012-06-16 18:51:20440 'FRIEND_TEST(',
441 (
[email protected]e3c945502012-06-26 20:01:49442 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20443 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
444 ),
445 False,
[email protected]7345da02012-11-27 14:31:49446 (),
[email protected]23e6cbc2012-06-16 18:51:20447 ),
448 (
Dave Tapuska98199b612019-07-10 13:30:44449 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53450 (
451 'Chrome clients wishing to select events on X windows should use',
452 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
453 'you are selecting events from the GPU process, or if you are using',
454 'an XDisplay other than gfx::GetXDisplay().',
455 ),
456 True,
457 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40458 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04459 r"^ui[\\/]gl[\\/].*\.cc$",
460 r"^media[\\/]gpu[\\/].*\.cc$",
461 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53462 ),
463 ),
464 (
Dave Tapuska98199b612019-07-10 13:30:44465 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20466 (
thomasanderson11aa41d2017-06-08 22:22:38467 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20468 ),
469 True,
470 (
Egor Paskoce145c42018-09-28 19:31:04471 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
472 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
473 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20474 ),
475 ),
476 (
tomhudsone2c14d552016-05-26 17:07:46477 'setMatrixClip',
478 (
479 'Overriding setMatrixClip() is prohibited; ',
480 'the base function is deprecated. ',
481 ),
482 True,
483 (),
484 ),
485 (
[email protected]52657f62013-05-20 05:30:31486 'SkRefPtr',
487 (
488 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22489 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31490 ),
491 True,
492 (),
493 ),
494 (
495 'SkAutoRef',
496 (
497 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
503 (
504 'SkAutoTUnref',
505 (
506 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22507 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31508 ),
509 True,
510 (),
511 ),
512 (
513 'SkAutoUnref',
514 (
515 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
516 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22517 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31518 ),
519 True,
520 (),
521 ),
[email protected]d89eec82013-12-03 14:10:59522 (
523 r'/HANDLE_EINTR\(.*close',
524 (
525 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
526 'descriptor will be closed, and it is incorrect to retry the close.',
527 'Either call close directly and ignore its return value, or wrap close',
528 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
529 ),
530 True,
531 (),
532 ),
533 (
534 r'/IGNORE_EINTR\((?!.*close)',
535 (
536 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
537 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
538 ),
539 True,
540 (
541 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04542 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
543 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59544 ),
545 ),
[email protected]ec5b3f02014-04-04 18:43:43546 (
547 r'/v8::Extension\(',
548 (
549 'Do not introduce new v8::Extensions into the code base, use',
550 'gin::Wrappable instead. See http://crbug.com/334679',
551 ),
552 True,
[email protected]f55c90ee62014-04-12 00:50:03553 (
Egor Paskoce145c42018-09-28 19:31:04554 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03555 ),
[email protected]ec5b3f02014-04-04 18:43:43556 ),
skyostilf9469f72015-04-20 10:38:52557 (
jame2d1a952016-04-02 00:27:10558 '#pragma comment(lib,',
559 (
560 'Specify libraries to link with in build files and not in the source.',
561 ),
562 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41563 (
tzik3f295992018-12-04 20:32:23564 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04565 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41566 ),
jame2d1a952016-04-02 00:27:10567 ),
fdorayc4ac18d2017-05-01 21:39:59568 (
Gabriel Charette7cc6c432018-04-25 20:52:02569 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59570 (
571 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
572 ),
573 False,
574 (),
575 ),
576 (
Gabriel Charette7cc6c432018-04-25 20:52:02577 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59578 (
579 'Consider using THREAD_CHECKER macros instead of the class directly.',
580 ),
581 False,
582 (),
583 ),
dbeamb6f4fde2017-06-15 04:03:06584 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06585 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
586 (
587 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
588 'deprecated (http://crbug.com/634507). Please avoid converting away',
589 'from the Time types in Chromium code, especially if any math is',
590 'being done on time values. For interfacing with platform/library',
591 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
592 'type converter methods instead. For faking TimeXXX values (for unit',
593 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
594 'other use cases, please contact base/time/OWNERS.',
595 ),
596 False,
597 (),
598 ),
599 (
dbeamb6f4fde2017-06-15 04:03:06600 'CallJavascriptFunctionUnsafe',
601 (
602 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
603 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
604 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
605 ),
606 False,
607 (
Egor Paskoce145c42018-09-28 19:31:04608 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
609 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
610 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06611 ),
612 ),
dskiba1474c2bfd62017-07-20 02:19:24613 (
614 'leveldb::DB::Open',
615 (
616 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
617 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
618 "Chrome's tracing, making their memory usage visible.",
619 ),
620 True,
621 (
622 r'^third_party/leveldatabase/.*\.(cc|h)$',
623 ),
Gabriel Charette0592c3a2017-07-26 12:02:04624 ),
625 (
Chris Mumfordc38afb62017-10-09 17:55:08626 'leveldb::NewMemEnv',
627 (
628 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58629 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
630 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08631 ),
632 True,
633 (
634 r'^third_party/leveldatabase/.*\.(cc|h)$',
635 ),
636 ),
637 (
Gabriel Charetted9839bc2017-07-29 14:17:47638 'RunLoop::QuitCurrent',
639 (
Robert Liao64b7ab22017-08-04 23:03:43640 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
641 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47642 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41643 False,
Gabriel Charetted9839bc2017-07-29 14:17:47644 (),
Gabriel Charettea44975052017-08-21 23:14:04645 ),
646 (
647 'base::ScopedMockTimeMessageLoopTaskRunner',
648 (
Gabriel Charette87cc1af2018-04-25 20:52:51649 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11650 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51651 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
652 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
653 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04654 ),
Gabriel Charette87cc1af2018-04-25 20:52:51655 False,
Gabriel Charettea44975052017-08-21 23:14:04656 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57657 ),
658 (
Dave Tapuska98199b612019-07-10 13:30:44659 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57660 (
661 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02662 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57663 ),
664 True,
665 (),
Francois Doray43670e32017-09-27 12:40:38666 ),
667 (
Peter Kasting991618a62019-06-17 22:00:09668 r'/\bstd::stoi\b',
669 (
670 'std::stoi uses exceptions to communicate results. ',
671 'Use base::StringToInt() instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
675 ),
676 (
677 r'/\bstd::stol\b',
678 (
679 'std::stol uses exceptions to communicate results. ',
680 'Use base::StringToInt() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stoul\b',
687 (
688 'std::stoul uses exceptions to communicate results. ',
689 'Use base::StringToUint() instead.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
695 r'/\bstd::stoll\b',
696 (
697 'std::stoll uses exceptions to communicate results. ',
698 'Use base::StringToInt64() instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
702 ),
703 (
704 r'/\bstd::stoull\b',
705 (
706 'std::stoull uses exceptions to communicate results. ',
707 'Use base::StringToUint64() instead.',
708 ),
709 True,
710 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
711 ),
712 (
713 r'/\bstd::stof\b',
714 (
715 'std::stof uses exceptions to communicate results. ',
716 'For locale-independent values, e.g. reading numbers from disk',
717 'profiles, use base::StringToDouble().',
718 'For user-visible values, parse using ICU.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
722 ),
723 (
724 r'/\bstd::stod\b',
725 (
726 'std::stod uses exceptions to communicate results. ',
727 'For locale-independent values, e.g. reading numbers from disk',
728 'profiles, use base::StringToDouble().',
729 'For user-visible values, parse using ICU.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::stold\b',
736 (
737 'std::stold uses exceptions to communicate results. ',
738 'For locale-independent values, e.g. reading numbers from disk',
739 'profiles, use base::StringToDouble().',
740 'For user-visible values, parse using ICU.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
Daniel Bratell69334cc2019-03-26 11:07:45746 r'/\bstd::to_string\b',
747 (
748 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09749 'For locale-independent strings, e.g. writing numbers to disk',
750 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45751 'For user-visible strings, use base::FormatNumber() and',
752 'the related functions in base/i18n/number_formatting.h.',
753 ),
Peter Kasting991618a62019-06-17 22:00:09754 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21755 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45756 ),
757 (
758 r'/\bstd::shared_ptr\b',
759 (
760 'std::shared_ptr should not be used. Use scoped_refptr instead.',
761 ),
762 True,
Andreas Haas63f58792019-11-07 10:56:44763 [_THIRD_PARTY_EXCEPT_BLINK,
764 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
765 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21766 ),
767 (
Peter Kasting991618a62019-06-17 22:00:09768 r'/\bstd::weak_ptr\b',
769 (
770 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
Daniel Bratell609102be2019-03-27 20:53:21776 r'/\blong long\b',
777 (
778 'long long is banned. Use stdint.h if you need a 64 bit number.',
779 ),
780 False, # Only a warning since it is already used.
781 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
782 ),
783 (
784 r'/\bstd::bind\b',
785 (
786 'std::bind is banned because of lifetime risks.',
787 'Use base::BindOnce or base::BindRepeating instead.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\b#include <chrono>\b',
794 (
795 '<chrono> overlaps with Time APIs in base. Keep using',
796 'base classes.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
800 ),
801 (
802 r'/\b#include <exception>\b',
803 (
804 'Exceptions are banned and disabled in Chromium.',
805 ),
806 True,
807 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
808 ),
809 (
810 r'/\bstd::function\b',
811 (
812 'std::function is banned. Instead use base::Callback which directly',
813 'supports Chromium\'s weak pointers, ref counting and more.',
814 ),
Peter Kasting991618a62019-06-17 22:00:09815 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21816 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
817 ),
818 (
819 r'/\b#include <random>\b',
820 (
821 'Do not use any random number engines from <random>. Instead',
822 'use base::RandomBitGenerator.',
823 ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
826 ),
827 (
828 r'/\bstd::ratio\b',
829 (
830 'std::ratio is banned by the Google Style Guide.',
831 ),
832 True,
833 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45834 ),
835 (
Francois Doray43670e32017-09-27 12:40:38836 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
837 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
838 (
839 'Use the new API in base/threading/thread_restrictions.h.',
840 ),
Gabriel Charette04b138f2018-08-06 00:03:22841 False,
Francois Doray43670e32017-09-27 12:40:38842 (),
843 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38844 (
danakj7a2b7082019-05-21 21:13:51845 r'/\bbase::Bind\(',
846 (
847 'Please use base::Bind{Once,Repeating} instead',
848 'of base::Bind. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Callback[<:]',
855 (
856 'Please use base::{Once,Repeating}Callback instead',
857 'of base::Callback. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
863 r'/\bbase::Closure\b',
864 (
865 'Please use base::{Once,Repeating}Closure instead',
866 'of base::Closure. (crbug.com/714018)',
867 ),
868 False,
Erik Staaba737d7602019-11-25 18:41:07869 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51870 ),
871 (
Michael Giuffrida7f93d6922019-04-19 14:39:58872 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 'RunMessageLoop is deprecated, use RunLoop instead.',
875 ),
876 False,
877 (),
878 ),
879 (
Dave Tapuska98199b612019-07-10 13:30:44880 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19881 (
882 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
891 "if you're convinced you need this.",
892 ),
893 False,
894 (),
895 ),
896 (
Dave Tapuska98199b612019-07-10 13:30:44897 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19898 (
899 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04900 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19901 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
902 'async events instead of flushing threads.',
903 ),
904 False,
905 (),
906 ),
907 (
908 r'MessageLoopRunner',
909 (
910 'MessageLoopRunner is deprecated, use RunLoop instead.',
911 ),
912 False,
913 (),
914 ),
915 (
Dave Tapuska98199b612019-07-10 13:30:44916 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19917 (
918 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
919 "gab@ if you found a use case where this is the only solution.",
920 ),
921 False,
922 (),
923 ),
924 (
Victor Costane48a2e82019-03-15 22:02:34925 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16926 (
Victor Costane48a2e82019-03-15 22:02:34927 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16928 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
929 ),
930 True,
931 (
932 r'^sql/initialization\.(cc|h)$',
933 r'^third_party/sqlite/.*\.(c|cc|h)$',
934 ),
935 ),
Matt Menke7f520a82018-03-28 21:38:37936 (
Dave Tapuska98199b612019-07-10 13:30:44937 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47938 (
939 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
940 'base::RandomShuffle instead.'
941 ),
942 True,
943 (),
944 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24945 (
946 'ios/web/public/test/http_server',
947 (
948 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
949 ),
950 False,
951 (),
952 ),
Robert Liao764c9492019-01-24 18:46:28953 (
954 'GetAddressOf',
955 (
956 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Robert Liaoe794041e2019-10-03 17:16:46957 'implicated in a few leaks. Use operator& instead. See ',
958 'http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28959 ),
960 True,
961 (),
962 ),
Antonio Gomes07300d02019-03-13 20:59:57963 (
964 'DEFINE_TYPE_CASTS',
965 (
966 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
967 '//third_party/blink/renderer/platform/casting.h.'
968 ),
969 True,
970 (
971 r'^third_party/blink/renderer/.*\.(cc|h)$',
972 ),
973 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38974 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45975 r'/\bIsHTML.+Element\(\b',
976 (
977 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
978 ' helpers IsA<HTMLXXXXElement> from ',
979 '//third_party/blink/renderer/platform/casting.h.'
980 ),
981 False,
982 (
983 r'^third_party/blink/renderer/.*\.(cc|h)$',
984 ),
985 ),
986 (
987 r'/\bToHTML.+Element(|OrNull)\(\b',
988 (
989 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
990 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
991 'and DynamicTo<HTMLXXXXElement> from ',
992 '//third_party/blink/renderer/platform/casting.h.'
993 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
994 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
995 ),
996 False,
997 (
998 r'^third_party/blink/renderer/.*\.(cc|h)$',
999 ),
1000 ),
1001 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371002 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381003 (
1004 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1005 ),
1006 True,
1007 (),
1008 ),
Ben Lewisa9514602019-04-29 17:53:051009 (
1010 'SHFileOperation',
1011 (
1012 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1013 'complex functions to achieve the same goals. Use IFileOperation for ',
1014 'any esoteric actions instead.'
1015 ),
1016 True,
1017 (),
1018 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181019 (
Cliff Smolinsky81951642019-04-30 21:39:511020 'StringFromGUID2',
1021 (
1022 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1023 'Use base::win::String16FromGUID instead.'
1024 ),
1025 True,
1026 (
1027 r'/base/win/win_util_unittest.cc'
1028 ),
1029 ),
1030 (
1031 'StringFromCLSID',
1032 (
1033 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1034 'Use base::win::String16FromGUID instead.'
1035 ),
1036 True,
1037 (
1038 r'/base/win/win_util_unittest.cc'
1039 ),
1040 ),
1041 (
Avi Drissman7382afa02019-04-29 23:27:131042 'kCFAllocatorNull',
1043 (
1044 'The use of kCFAllocatorNull with the NoCopy creation of ',
1045 'CoreFoundation types is prohibited.',
1046 ),
1047 True,
1048 (),
1049 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291050 (
1051 'mojo::ConvertTo',
1052 (
1053 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1054 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1055 'StringTraits if you would like to convert between custom types and',
1056 'the wire format of mojom types.'
1057 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221058 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291059 (
Wezf89dec092019-09-11 19:38:331060 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1061 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291062 r'^third_party/blink/.*\.(cc|h)$',
1063 r'^content/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Robert Liao1d78df52019-11-11 20:02:011066 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161067 'GetInterfaceProvider',
1068 (
1069 'InterfaceProvider is deprecated.',
1070 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1071 'or Platform::GetBrowserInterfaceBroker.'
1072 ),
1073 False,
1074 (),
1075 ),
1076 (
Robert Liao1d78df52019-11-11 20:02:011077 'CComPtr',
1078 (
1079 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1080 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1081 'details.'
1082 ),
1083 False,
1084 (),
1085 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201086 (
1087 r'/\b(IFACE|STD)METHOD_?\(',
1088 (
1089 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1090 'Instead, always use IFACEMETHODIMP in the declaration.'
1091 ),
1092 False,
1093 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1094 ),
Allen Bauer53b43fb12020-03-12 17:21:471095 (
1096 'set_owned_by_client',
1097 (
1098 'set_owned_by_client is deprecated.',
1099 'views::View already owns the child views by default. This introduces ',
1100 'a competing ownership model which makes the code difficult to reason ',
1101 'about. See http://crbug.com/1044687 for more details.'
1102 ),
1103 False,
1104 (),
1105 ),
Eric Secklerbe6f48d2020-05-06 18:09:121106 (
1107 r'/\bTRACE_EVENT_ASYNC_',
1108 (
1109 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1110 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1111 ),
1112 False,
1113 (
1114 r'^base/trace_event/.*',
1115 r'^base/tracing/.*',
1116 ),
1117 ),
[email protected]127f18ec2012-06-16 05:05:591118)
1119
Mario Sanchez Prada2472cab2019-09-18 10:58:311120# Format: Sequence of tuples containing:
1121# * String pattern or, if starting with a slash, a regular expression.
1122# * Sequence of strings to show when the pattern matches.
1123_DEPRECATED_MOJO_TYPES = (
1124 (
1125 r'/\bmojo::AssociatedBinding\b',
1126 (
1127 'mojo::AssociatedBinding<Interface> is deprecated.',
1128 'Use mojo::AssociatedReceiver<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::AssociatedBindingSet\b',
1133 (
1134 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1135 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::AssociatedInterfacePtr\b',
1140 (
1141 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1142 'Use mojo::AssociatedRemote<Interface> instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1147 (
1148 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1149 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1150 ),
1151 ),
1152 (
1153 r'/\bmojo::AssociatedInterfaceRequest\b',
1154 (
1155 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1156 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1157 ),
1158 ),
1159 (
1160 r'/\bmojo::Binding\b',
1161 (
1162 'mojo::Binding<Interface> is deprecated.',
1163 'Use mojo::Receiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::BindingSet\b',
1168 (
1169 'mojo::BindingSet<Interface> is deprecated.',
1170 'Use mojo::ReceiverSet<Interface> instead.',
1171 ),
1172 ),
1173 (
1174 r'/\bmojo::InterfacePtr\b',
1175 (
1176 'mojo::InterfacePtr<Interface> is deprecated.',
1177 'Use mojo::Remote<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::InterfacePtrInfo\b',
1182 (
1183 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1184 'Use mojo::PendingRemote<Interface> instead.',
1185 ),
1186 ),
1187 (
1188 r'/\bmojo::InterfaceRequest\b',
1189 (
1190 'mojo::InterfaceRequest<Interface> is deprecated.',
1191 'Use mojo::PendingReceiver<Interface> instead.',
1192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeRequest\b',
1196 (
1197 'mojo::MakeRequest is deprecated.',
1198 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1203 (
1204 'mojo::MakeRequest is deprecated.',
1205 'Use mojo::AssociatedRemote::'
1206 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongBinding\b',
1211 (
1212 'mojo::MakeStrongBinding is deprecated.',
1213 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1214 'mojo::MakeSelfOwnedReceiver() instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::MakeStrongAssociatedBinding\b',
1219 (
1220 'mojo::MakeStrongAssociatedBinding is deprecated.',
1221 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1222 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1223 ),
1224 ),
1225 (
1226 r'/\bmojo::StrongAssociatedBindingSet\b',
1227 (
1228 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1229 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1230 ),
1231 ),
1232 (
1233 r'/\bmojo::StrongBindingSet\b',
1234 (
1235 'mojo::StrongBindingSet<Interface> is deprecated.',
1236 'Use mojo::UniqueReceiverSet<Interface> instead.',
1237 ),
1238 ),
1239)
wnwenbdc444e2016-05-25 13:44:151240
mlamouria82272622014-09-16 18:45:041241_IPC_ENUM_TRAITS_DEPRECATED = (
1242 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501243 'See http://www.chromium.org/Home/chromium-security/education/'
1244 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041245
Stephen Martinis97a394142018-06-07 23:06:051246_LONG_PATH_ERROR = (
1247 'Some files included in this CL have file names that are too long (> 200'
1248 ' characters). If committed, these files will cause issues on Windows. See'
1249 ' https://crbug.com/612667 for more details.'
1250)
1251
Shenghua Zhangbfaa38b82017-11-16 21:58:021252_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041253 r".*[\\/]BuildHooksAndroidImpl\.java",
1254 r".*[\\/]LicenseContentProvider\.java",
1255 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281256 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021257]
[email protected]127f18ec2012-06-16 05:05:591258
Mohamed Heikald048240a2019-11-12 16:57:371259# List of image extensions that are used as resources in chromium.
1260_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1261
Sean Kau46e29bc2017-08-28 16:31:161262# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401263_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041264 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401265 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041266 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1267 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041268 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431269 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161270]
1271
1272
[email protected]b00342e7f2013-03-26 16:21:541273_VALID_OS_MACROS = (
1274 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081275 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541276 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121277 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_BSD',
1279 'OS_CAT', # For testing.
1280 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041281 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371283 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_IOS',
1285 'OS_LINUX',
1286 'OS_MACOSX',
1287 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211288 'OS_NACL_NONSFI',
1289 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121290 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_OPENBSD',
1292 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371293 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_WIN',
1296)
1297
1298
agrievef32bcc72016-04-04 14:57:401299_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391300 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361301 'base/android/jni_generator/jni_generator.pydeps',
1302 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:221303 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361304 'build/android/gyp/aar.pydeps',
1305 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271306 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381308 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111310 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361312 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111314 'build/android/gyp/create_app_bundle_apks.pydeps',
1315 'build/android/gyp/create_app_bundle.pydeps',
1316 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221318 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591320 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361321 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421322 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/filter_zip.pydeps',
1325 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361326 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581328 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361329 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261330 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011331 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/jinja_template.pydeps',
1333 'build/android/gyp/lint.pydeps',
1334 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/merge_manifest.pydeps',
1336 'build/android/gyp/prepare_resources.pydeps',
1337 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461338 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241339 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461341 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561342 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/incremental_install/generate_android_manifest.pydeps',
1344 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221345 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:401346 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:041347 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:411349 'chrome/android/features/create_stripped_java_factory.pydeps',
Tibor Goldschwendtc748dfca42019-10-24 19:39:051350 'components/module_installer/android/module_desc_java.pydeps',
agrieve732db3a2016-04-26 19:18:191351 'net/tools/testserver/testserver.pydeps',
Andrew Luo338fe6e82019-09-19 07:17:431352 'testing/scripts/run_android_wpt.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:021353 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:401354]
1355
wnwenbdc444e2016-05-25 13:44:151356
agrievef32bcc72016-04-04 14:57:401357_GENERIC_PYDEPS_FILES = [
anthonyvd7323c982019-09-11 14:36:421358 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131359 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421360 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1361 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131362 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191363 ('third_party/blink/renderer/bindings/scripts/'
1364 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061365 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221366 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401367]
1368
wnwenbdc444e2016-05-25 13:44:151369
agrievef32bcc72016-04-04 14:57:401370_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1371
1372
Eric Boren6fd2b932018-01-25 15:05:081373# Bypass the AUTHORS check for these accounts.
1374_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591375 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451376 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591377 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521378 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1379 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041380 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271381 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041382 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301383 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081384
1385
Daniel Bratell65b033262019-04-23 08:17:061386def _IsCPlusPlusFile(input_api, file_path):
1387 """Returns True if this file contains C++-like code (and not Python,
1388 Go, Java, MarkDown, ...)"""
1389
1390 ext = input_api.os_path.splitext(file_path)[1]
1391 # This list is compatible with CppChecker.IsCppFile but we should
1392 # consider adding ".c" to it. If we do that we can use this function
1393 # at more places in the code.
1394 return ext in (
1395 '.h',
1396 '.cc',
1397 '.cpp',
1398 '.m',
1399 '.mm',
1400 )
1401
1402def _IsCPlusPlusHeaderFile(input_api, file_path):
1403 return input_api.os_path.splitext(file_path)[1] == ".h"
1404
1405
1406def _IsJavaFile(input_api, file_path):
1407 return input_api.os_path.splitext(file_path)[1] == ".java"
1408
1409
1410def _IsProtoFile(input_api, file_path):
1411 return input_api.os_path.splitext(file_path)[1] == ".proto"
1412
[email protected]55459852011-08-10 15:17:191413def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1414 """Attempts to prevent use of functions intended only for testing in
1415 non-testing code. For now this is just a best-effort implementation
1416 that ignores header files and may have some false positives. A
1417 better implementation would probably need a proper C++ parser.
1418 """
1419 # We only scan .cc files and the like, as the declaration of
1420 # for-testing functions in header files are hard to distinguish from
1421 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491422 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191423
jochenc0d4808c2015-07-27 09:25:421424 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191425 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091426 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191427 exclusion_pattern = input_api.re.compile(
1428 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1429 base_function_pattern, base_function_pattern))
1430
1431 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441432 black_list = (_EXCLUDED_PATHS +
1433 _TEST_CODE_EXCLUDED_PATHS +
1434 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191435 return input_api.FilterSourceFile(
1436 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491437 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191438 black_list=black_list)
1439
1440 problems = []
1441 for f in input_api.AffectedSourceFiles(FilterFile):
1442 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241443 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031444 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461445 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031446 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191447 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031448 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191449
1450 if problems:
[email protected]f7051d52013-04-02 18:31:421451 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031452 else:
1453 return []
[email protected]55459852011-08-10 15:17:191454
1455
Vaclav Brozek7dbc28c2018-03-27 08:35:231456def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1457 """This is a simplified version of
1458 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1459 """
1460 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1461 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1462 name_pattern = r'ForTest(s|ing)?'
1463 # Describes an occurrence of "ForTest*" inside a // comment.
1464 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1465 # Catch calls.
1466 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1467 # Ignore definitions. (Comments are ignored separately.)
1468 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1469
1470 problems = []
1471 sources = lambda x: input_api.FilterSourceFile(
1472 x,
1473 black_list=(('(?i).*test', r'.*\/junit\/')
1474 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491475 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231476 )
1477 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1478 local_path = f.LocalPath()
1479 is_inside_javadoc = False
1480 for line_number, line in f.ChangedContents():
1481 if is_inside_javadoc and javadoc_end_re.search(line):
1482 is_inside_javadoc = False
1483 if not is_inside_javadoc and javadoc_start_re.search(line):
1484 is_inside_javadoc = True
1485 if is_inside_javadoc:
1486 continue
1487 if (inclusion_re.search(line) and
1488 not comment_re.search(line) and
1489 not exclusion_re.search(line)):
1490 problems.append(
1491 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1492
1493 if problems:
1494 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1495 else:
1496 return []
1497
1498
[email protected]10689ca2011-09-02 02:31:541499def _CheckNoIOStreamInHeaders(input_api, output_api):
1500 """Checks to make sure no .h files include <iostream>."""
1501 files = []
1502 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1503 input_api.re.MULTILINE)
1504 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1505 if not f.LocalPath().endswith('.h'):
1506 continue
1507 contents = input_api.ReadFile(f)
1508 if pattern.search(contents):
1509 files.append(f)
1510
1511 if len(files):
yolandyandaabc6d2016-04-18 18:29:391512 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061513 'Do not #include <iostream> in header files, since it inserts static '
1514 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541515 '#include <ostream>. See http://crbug.com/94794',
1516 files) ]
1517 return []
1518
Danil Chapovalov3518f362018-08-11 16:13:431519def _CheckNoStrCatRedefines(input_api, output_api):
1520 """Checks no windows headers with StrCat redefined are included directly."""
1521 files = []
1522 pattern_deny = input_api.re.compile(
1523 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1524 input_api.re.MULTILINE)
1525 pattern_allow = input_api.re.compile(
1526 r'^#include\s"base/win/windows_defines.inc"',
1527 input_api.re.MULTILINE)
1528 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1529 contents = input_api.ReadFile(f)
1530 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1531 files.append(f.LocalPath())
1532
1533 if len(files):
1534 return [output_api.PresubmitError(
1535 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1536 'directly since they pollute code with StrCat macro. Instead, '
1537 'include matching header from base/win. See http://crbug.com/856536',
1538 files) ]
1539 return []
1540
[email protected]10689ca2011-09-02 02:31:541541
[email protected]72df4e782012-06-21 16:28:181542def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521543 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181544 problems = []
1545 for f in input_api.AffectedFiles():
1546 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1547 continue
1548
1549 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041550 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181551 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1552
1553 if not problems:
1554 return []
1555 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1556 '\n'.join(problems))]
1557
Dominic Battre033531052018-09-24 15:45:341558def _CheckNoDISABLETypoInTests(input_api, output_api):
1559 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1560
1561 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1562 instead of DISABLED_. To filter false positives, reports are only generated
1563 if a corresponding MAYBE_ line exists.
1564 """
1565 problems = []
1566
1567 # The following two patterns are looked for in tandem - is a test labeled
1568 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1569 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1570 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1571
1572 # This is for the case that a test is disabled on all platforms.
1573 full_disable_pattern = input_api.re.compile(
1574 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1575 input_api.re.MULTILINE)
1576
Katie Df13948e2018-09-25 07:33:441577 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341578 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1579 continue
1580
1581 # Search for MABYE_, DISABLE_ pairs.
1582 disable_lines = {} # Maps of test name to line number.
1583 maybe_lines = {}
1584 for line_num, line in f.ChangedContents():
1585 disable_match = disable_pattern.search(line)
1586 if disable_match:
1587 disable_lines[disable_match.group(1)] = line_num
1588 maybe_match = maybe_pattern.search(line)
1589 if maybe_match:
1590 maybe_lines[maybe_match.group(1)] = line_num
1591
1592 # Search for DISABLE_ occurrences within a TEST() macro.
1593 disable_tests = set(disable_lines.keys())
1594 maybe_tests = set(maybe_lines.keys())
1595 for test in disable_tests.intersection(maybe_tests):
1596 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1597
1598 contents = input_api.ReadFile(f)
1599 full_disable_match = full_disable_pattern.search(contents)
1600 if full_disable_match:
1601 problems.append(' %s' % f.LocalPath())
1602
1603 if not problems:
1604 return []
1605 return [
1606 output_api.PresubmitPromptWarning(
1607 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1608 '\n'.join(problems))
1609 ]
1610
[email protected]72df4e782012-06-21 16:28:181611
danakj61c1aa22015-10-26 19:55:521612def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571613 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521614 errors = []
1615 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1616 input_api.re.MULTILINE)
1617 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1618 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1619 continue
1620 for lnum, line in f.ChangedContents():
1621 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171622 errors.append(output_api.PresubmitError(
1623 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571624 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171625 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521626 return errors
1627
1628
Makoto Shimazu3ad422cd2019-05-08 02:35:141629def _FindHistogramNameInChunk(histogram_name, chunk):
1630 """Tries to find a histogram name or prefix in a line.
1631
1632 Returns the existence of the histogram name, or None if it needs more chunk
1633 to determine."""
mcasasb7440c282015-02-04 14:52:191634 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1635 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141636 if '<affected-histogram' in chunk:
1637 # If the tag is not completed, needs more chunk to get the name.
1638 if not '>' in chunk:
1639 return None
1640 if not 'name="' in chunk:
1641 return False
1642 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1643 # expect the only attribute is the name.
1644 histogram_prefix = chunk.split('"')[1]
1645 return histogram_prefix in histogram_name
1646 # Typically the whole histogram name should in the line.
1647 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191648
1649
1650def _CheckUmaHistogramChanges(input_api, output_api):
1651 """Check that UMA histogram names in touched lines can still be found in other
1652 lines of the patch or in histograms.xml. Note that this check would not catch
1653 the reverse: changes in histograms.xml not matched in the code itself."""
1654 touched_histograms = []
1655 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471656 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1657 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1658 name_pattern = r'"(.*?)"'
1659 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1660 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1661 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1662 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1663 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171664 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191665 for f in input_api.AffectedFiles():
1666 # If histograms.xml itself is modified, keep the modified lines for later.
1667 if f.LocalPath().endswith(('histograms.xml')):
1668 histograms_xml_modifications = f.ChangedContents()
1669 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471670 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1671 single_line_re = single_line_c_re
1672 split_line_prefix_re = split_line_c_prefix_re
1673 elif f.LocalPath().endswith(('java')):
1674 single_line_re = single_line_java_re
1675 split_line_prefix_re = split_line_java_prefix_re
1676 else:
mcasasb7440c282015-02-04 14:52:191677 continue
1678 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171679 if last_line_matched_prefix:
1680 suffix_found = split_line_suffix_re.search(line)
1681 if suffix_found :
1682 touched_histograms.append([suffix_found.group(1), f, line_num])
1683 last_line_matched_prefix = False
1684 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061685 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191686 if found:
1687 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171688 continue
1689 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191690
1691 # Search for the touched histogram names in the local modifications to
1692 # histograms.xml, and, if not found, on the base histograms.xml file.
1693 unmatched_histograms = []
1694 for histogram_info in touched_histograms:
1695 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141696 chunk = ''
mcasasb7440c282015-02-04 14:52:191697 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141698 chunk += line
1699 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1700 if histogram_name_found is None:
1701 continue
1702 chunk = ''
mcasasb7440c282015-02-04 14:52:191703 if histogram_name_found:
1704 break
1705 if not histogram_name_found:
1706 unmatched_histograms.append(histogram_info)
1707
eromanb90c82e7e32015-04-01 15:13:491708 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191709 problems = []
1710 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491711 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191712 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451713 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191714 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141715 chunk = ''
mcasasb7440c282015-02-04 14:52:191716 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141717 chunk += line
1718 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1719 chunk)
1720 if histogram_name_found is None:
1721 continue
1722 chunk = ''
mcasasb7440c282015-02-04 14:52:191723 if histogram_name_found:
1724 break
1725 if not histogram_name_found:
1726 problems.append(' [%s:%d] %s' %
1727 (f.LocalPath(), line_num, histogram_name))
1728
1729 if not problems:
1730 return []
1731 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1732 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491733 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191734
wnwenbdc444e2016-05-25 13:44:151735
yolandyandaabc6d2016-04-18 18:29:391736def _CheckFlakyTestUsage(input_api, output_api):
1737 """Check that FlakyTest annotation is our own instead of the android one"""
1738 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1739 files = []
1740 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1741 if f.LocalPath().endswith('Test.java'):
1742 if pattern.search(input_api.ReadFile(f)):
1743 files.append(f)
1744 if len(files):
1745 return [output_api.PresubmitError(
1746 'Use org.chromium.base.test.util.FlakyTest instead of '
1747 'android.test.FlakyTest',
1748 files)]
1749 return []
mcasasb7440c282015-02-04 14:52:191750
wnwenbdc444e2016-05-25 13:44:151751
[email protected]8ea5d4b2011-09-13 21:49:221752def _CheckNoNewWStrings(input_api, output_api):
1753 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271754 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221755 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201756 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571757 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341758 '/win/' in f.LocalPath() or
1759 'chrome_elf' in f.LocalPath() or
1760 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201761 continue
[email protected]8ea5d4b2011-09-13 21:49:221762
[email protected]a11dbe9b2012-08-07 01:32:581763 allowWString = False
[email protected]b5c24292011-11-28 14:38:201764 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581765 if 'presubmit: allow wstring' in line:
1766 allowWString = True
1767 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271768 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581769 allowWString = False
1770 else:
1771 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221772
[email protected]55463aa62011-10-12 00:48:271773 if not problems:
1774 return []
1775 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581776 ' If you are calling a cross-platform API that accepts a wstring, '
1777 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271778 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221779
1780
[email protected]2a8ac9c2011-10-19 17:20:441781def _CheckNoDEPSGIT(input_api, output_api):
1782 """Make sure .DEPS.git is never modified manually."""
1783 if any(f.LocalPath().endswith('.DEPS.git') for f in
1784 input_api.AffectedFiles()):
1785 return [output_api.PresubmitError(
1786 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1787 'automated system based on what\'s in DEPS and your changes will be\n'
1788 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501789 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1790 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441791 'for more information')]
1792 return []
1793
1794
tandriief664692014-09-23 14:51:471795def _CheckValidHostsInDEPS(input_api, output_api):
1796 """Checks that DEPS file deps are from allowed_hosts."""
1797 # Run only if DEPS file has been modified to annoy fewer bystanders.
1798 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1799 return []
1800 # Outsource work to gclient verify
1801 try:
John Budorickf20c0042019-04-25 23:23:401802 gclient_path = input_api.os_path.join(
1803 input_api.PresubmitLocalPath(),
1804 'third_party', 'depot_tools', 'gclient.py')
1805 input_api.subprocess.check_output(
1806 [input_api.python_executable, gclient_path, 'verify'],
1807 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471808 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201809 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471810 return [output_api.PresubmitError(
1811 'DEPS file must have only git dependencies.',
1812 long_text=error.output)]
1813
1814
Mario Sanchez Prada2472cab2019-09-18 10:58:311815def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1816 type_name, message):
1817 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1818
1819 Returns an string composed of the name of the file, the line number where the
1820 match has been found and the additional text passed as |message| in case the
1821 target type name matches the text inside the line passed as parameter.
1822 """
1823 matched = False
1824 if type_name[0:1] == '/':
1825 regex = type_name[1:]
1826 if input_api.re.search(regex, line):
1827 matched = True
1828 elif type_name in line:
1829 matched = True
1830
1831 result = []
1832 if matched:
1833 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1834 for message_line in message:
1835 result.append(' %s' % message_line)
1836
1837 return result
1838
1839
[email protected]127f18ec2012-06-16 05:05:591840def _CheckNoBannedFunctions(input_api, output_api):
1841 """Make sure that banned functions are not used."""
1842 warnings = []
1843 errors = []
1844
wnwenbdc444e2016-05-25 13:44:151845 def IsBlacklisted(affected_file, blacklist):
1846 local_path = affected_file.LocalPath()
1847 for item in blacklist:
1848 if input_api.re.match(item, local_path):
1849 return True
1850 return False
1851
Peter K. Lee6c03ccff2019-07-15 14:40:051852 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541853 local_path = affected_file.LocalPath()
1854 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1855 return False
1856 basename = input_api.os_path.basename(local_path)
1857 if 'ios' in basename.split('_'):
1858 return True
1859 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1860 if sep and 'ios' in local_path.split(sep):
1861 return True
1862 return False
1863
wnwenbdc444e2016-05-25 13:44:151864 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311865 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1866 func_name, message)
1867 if problems:
wnwenbdc444e2016-05-25 13:44:151868 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311869 errors.extend(problems)
1870 else:
1871 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151872
Eric Stevensona9a980972017-09-23 00:04:411873 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1874 for f in input_api.AffectedFiles(file_filter=file_filter):
1875 for line_num, line in f.ChangedContents():
1876 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1877 CheckForMatch(f, line_num, line, func_name, message, error)
1878
[email protected]127f18ec2012-06-16 05:05:591879 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1880 for f in input_api.AffectedFiles(file_filter=file_filter):
1881 for line_num, line in f.ChangedContents():
1882 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151883 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591884
Peter K. Lee6c03ccff2019-07-15 14:40:051885 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541886 for line_num, line in f.ChangedContents():
1887 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1888 CheckForMatch(f, line_num, line, func_name, message, error)
1889
Peter K. Lee6c03ccff2019-07-15 14:40:051890 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1891 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1892 for line_num, line in f.ChangedContents():
1893 for func_name, message, error in _BANNED_IOS_EGTEST_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(('.cc', '.mm', '.h'))
1897 for f in input_api.AffectedFiles(file_filter=file_filter):
1898 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491899 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491900 if IsBlacklisted(f, excluded_paths):
1901 continue
wnwenbdc444e2016-05-25 13:44:151902 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591903
1904 result = []
1905 if (warnings):
1906 result.append(output_api.PresubmitPromptWarning(
1907 'Banned functions were used.\n' + '\n'.join(warnings)))
1908 if (errors):
1909 result.append(output_api.PresubmitError(
1910 'Banned functions were used.\n' + '\n'.join(errors)))
1911 return result
1912
1913
Michael Thiessen44457642020-02-06 00:24:151914def _CheckAndroidNoBannedImports(input_api, output_api):
1915 """Make sure that banned java imports are not used."""
1916 errors = []
1917
1918 def IsException(path, exceptions):
1919 for exception in exceptions:
1920 if (path.startswith(exception)):
1921 return True
1922 return False
1923
1924 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1925 for f in input_api.AffectedFiles(file_filter=file_filter):
1926 for line_num, line in f.ChangedContents():
1927 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1928 if IsException(f.LocalPath(), exceptions):
1929 continue;
1930 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1931 'import ' + import_name, message)
1932 if problems:
1933 errors.extend(problems)
1934 result = []
1935 if (errors):
1936 result.append(output_api.PresubmitError(
1937 'Banned imports were used.\n' + '\n'.join(errors)))
1938 return result
1939
1940
Mario Sanchez Prada2472cab2019-09-18 10:58:311941def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1942 """Make sure that old Mojo types are not used."""
1943 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571944 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311945
Mario Sanchez Pradaaab91382019-12-19 08:57:091946 # For any path that is not an "ok" or an "error" path, a warning will be
1947 # raised if deprecated mojo types are found.
1948 ok_paths = ['components/arc']
1949 error_paths = ['third_party/blink', 'content']
1950
Mario Sanchez Prada2472cab2019-09-18 10:58:311951 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1952 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571953 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091954 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311955 continue
1956
1957 for line_num, line in f.ChangedContents():
1958 for func_name, message in _DEPRECATED_MOJO_TYPES:
1959 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1960 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571961
Mario Sanchez Prada2472cab2019-09-18 10:58:311962 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091963 # Raise errors inside |error_paths| and warnings everywhere else.
1964 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571965 errors.extend(problems)
1966 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311967 warnings.extend(problems)
1968
1969 result = []
1970 if (warnings):
1971 result.append(output_api.PresubmitPromptWarning(
1972 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571973 if (errors):
1974 result.append(output_api.PresubmitError(
1975 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311976 return result
1977
1978
[email protected]6c063c62012-07-11 19:11:061979def _CheckNoPragmaOnce(input_api, output_api):
1980 """Make sure that banned functions are not used."""
1981 files = []
1982 pattern = input_api.re.compile(r'^#pragma\s+once',
1983 input_api.re.MULTILINE)
1984 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1985 if not f.LocalPath().endswith('.h'):
1986 continue
1987 contents = input_api.ReadFile(f)
1988 if pattern.search(contents):
1989 files.append(f)
1990
1991 if files:
1992 return [output_api.PresubmitError(
1993 'Do not use #pragma once in header files.\n'
1994 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1995 files)]
1996 return []
1997
[email protected]127f18ec2012-06-16 05:05:591998
[email protected]e7479052012-09-19 00:26:121999def _CheckNoTrinaryTrueFalse(input_api, output_api):
2000 """Checks to make sure we don't introduce use of foo ? true : false."""
2001 problems = []
2002 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2003 for f in input_api.AffectedFiles():
2004 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2005 continue
2006
2007 for line_num, line in f.ChangedContents():
2008 if pattern.match(line):
2009 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2010
2011 if not problems:
2012 return []
2013 return [output_api.PresubmitPromptWarning(
2014 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2015 '\n'.join(problems))]
2016
2017
[email protected]55f9f382012-07-31 11:02:182018def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282019 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182020 change. Breaking - rules is an error, breaking ! rules is a
2021 warning.
2022 """
mohan.reddyf21db962014-10-16 12:26:472023 import sys
[email protected]55f9f382012-07-31 11:02:182024 # We need to wait until we have an input_api object and use this
2025 # roundabout construct to import checkdeps because this file is
2026 # eval-ed and thus doesn't have __file__.
2027 original_sys_path = sys.path
2028 try:
2029 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472030 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182031 import checkdeps
[email protected]55f9f382012-07-31 11:02:182032 from rules import Rule
2033 finally:
2034 # Restore sys.path to what it was before.
2035 sys.path = original_sys_path
2036
2037 added_includes = []
rhalavati08acd232017-04-03 07:23:282038 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242039 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182040 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062041 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502042 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082043 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062044 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502045 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082046 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062047 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502048 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082049 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182050
[email protected]26385172013-05-09 23:11:352051 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182052
2053 error_descriptions = []
2054 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282055 error_subjects = set()
2056 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182057 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2058 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082059 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182060 description_with_path = '%s\n %s' % (path, rule_description)
2061 if rule_type == Rule.DISALLOW:
2062 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282063 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182064 else:
2065 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282066 warning_subjects.add("#includes")
2067
2068 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2069 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082070 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282071 description_with_path = '%s\n %s' % (path, rule_description)
2072 if rule_type == Rule.DISALLOW:
2073 error_descriptions.append(description_with_path)
2074 error_subjects.add("imports")
2075 else:
2076 warning_descriptions.append(description_with_path)
2077 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182078
Jinsuk Kim5a092672017-10-24 22:42:242079 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022080 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082081 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242082 description_with_path = '%s\n %s' % (path, rule_description)
2083 if rule_type == Rule.DISALLOW:
2084 error_descriptions.append(description_with_path)
2085 error_subjects.add("imports")
2086 else:
2087 warning_descriptions.append(description_with_path)
2088 warning_subjects.add("imports")
2089
[email protected]55f9f382012-07-31 11:02:182090 results = []
2091 if error_descriptions:
2092 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282093 'You added one or more %s that violate checkdeps rules.'
2094 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182095 error_descriptions))
2096 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422097 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282098 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182099 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282100 '%s? See relevant DEPS file(s) for details and contacts.' %
2101 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182102 warning_descriptions))
2103 return results
2104
2105
[email protected]fbcafe5a2012-08-08 15:31:222106def _CheckFilePermissions(input_api, output_api):
2107 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152108 if input_api.platform == 'win32':
2109 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292110 checkperms_tool = input_api.os_path.join(
2111 input_api.PresubmitLocalPath(),
2112 'tools', 'checkperms', 'checkperms.py')
2113 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472114 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392115 with input_api.CreateTemporaryFile() as file_list:
2116 for f in input_api.AffectedFiles():
2117 # checkperms.py file/directory arguments must be relative to the
2118 # repository.
2119 file_list.write(f.LocalPath() + '\n')
2120 file_list.close()
2121 args += ['--file-list', file_list.name]
2122 try:
2123 input_api.subprocess.check_output(args)
2124 return []
2125 except input_api.subprocess.CalledProcessError as error:
2126 return [output_api.PresubmitError(
2127 'checkperms.py failed:',
2128 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222129
2130
robertocn832f5992017-01-04 19:01:302131def _CheckTeamTags(input_api, output_api):
2132 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2133 checkteamtags_tool = input_api.os_path.join(
2134 input_api.PresubmitLocalPath(),
2135 'tools', 'checkteamtags', 'checkteamtags.py')
2136 args = [input_api.python_executable, checkteamtags_tool,
2137 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222138 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302139 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2140 'OWNERS']
2141 try:
2142 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052143 warnings = input_api.subprocess.check_output(args + files).splitlines()
2144 if warnings:
2145 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302146 return []
2147 except input_api.subprocess.CalledProcessError as error:
2148 return [output_api.PresubmitError(
2149 'checkteamtags.py failed:',
2150 long_text=error.output)]
2151
2152
[email protected]c8278b32012-10-30 20:35:492153def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2154 """Makes sure we don't include ui/aura/window_property.h
2155 in header files.
2156 """
2157 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2158 errors = []
2159 for f in input_api.AffectedFiles():
2160 if not f.LocalPath().endswith('.h'):
2161 continue
2162 for line_num, line in f.ChangedContents():
2163 if pattern.match(line):
2164 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2165
2166 results = []
2167 if errors:
2168 results.append(output_api.PresubmitError(
2169 'Header files should not include ui/aura/window_property.h', errors))
2170 return results
2171
2172
[email protected]70ca77752012-11-20 03:45:032173def _CheckForVersionControlConflictsInFile(input_api, f):
2174 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2175 errors = []
2176 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162177 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232178 # First-level headers in markdown look a lot like version control
2179 # conflict markers. http://daringfireball.net/projects/markdown/basics
2180 continue
[email protected]70ca77752012-11-20 03:45:032181 if pattern.match(line):
2182 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2183 return errors
2184
2185
2186def _CheckForVersionControlConflicts(input_api, output_api):
2187 """Usually this is not intentional and will cause a compile failure."""
2188 errors = []
2189 for f in input_api.AffectedFiles():
2190 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2191
2192 results = []
2193 if errors:
2194 results.append(output_api.PresubmitError(
2195 'Version control conflict markers found, please resolve.', errors))
2196 return results
2197
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202198
estadee17314a02017-01-12 16:22:162199def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2200 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2201 errors = []
2202 for f in input_api.AffectedFiles():
2203 for line_num, line in f.ChangedContents():
2204 if pattern.search(line):
2205 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2206
2207 results = []
2208 if errors:
2209 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502210 'Found Google support URL addressed by answer number. Please replace '
2211 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162212 return results
2213
[email protected]70ca77752012-11-20 03:45:032214
[email protected]06e6d0ff2012-12-11 01:36:442215def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2216 def FilterFile(affected_file):
2217 """Filter function for use with input_api.AffectedSourceFiles,
2218 below. This filters out everything except non-test files from
2219 top-level directories that generally speaking should not hard-code
2220 service URLs (e.g. src/android_webview/, src/content/ and others).
2221 """
2222 return input_api.FilterSourceFile(
2223 affected_file,
Egor Paskoce145c42018-09-28 19:31:042224 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442225 black_list=(_EXCLUDED_PATHS +
2226 _TEST_CODE_EXCLUDED_PATHS +
2227 input_api.DEFAULT_BLACK_LIST))
2228
reillyi38965732015-11-16 18:27:332229 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2230 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462231 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2232 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442233 problems = [] # items are (filename, line_number, line)
2234 for f in input_api.AffectedSourceFiles(FilterFile):
2235 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462236 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442237 problems.append((f.LocalPath(), line_num, line))
2238
2239 if problems:
[email protected]f7051d52013-04-02 18:31:422240 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442241 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582242 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442243 [' %s:%d: %s' % (
2244 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032245 else:
2246 return []
[email protected]06e6d0ff2012-12-11 01:36:442247
2248
James Cook6b6597c2019-11-06 22:05:292249def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2250 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2251 def FileFilter(affected_file):
2252 """Includes directories known to be Chrome OS only."""
2253 return input_api.FilterSourceFile(
2254 affected_file,
2255 white_list=('^ash/',
2256 '^chromeos/', # Top-level src/chromeos.
2257 '/chromeos/', # Any path component.
2258 '^components/arc',
2259 '^components/exo'),
2260 black_list=(input_api.DEFAULT_BLACK_LIST))
2261
2262 prefs = []
2263 priority_prefs = []
2264 for f in input_api.AffectedFiles(file_filter=FileFilter):
2265 for line_num, line in f.ChangedContents():
2266 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2267 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2268 prefs.append(' %s' % line)
2269 if input_api.re.search(
2270 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2271 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2272 priority_prefs.append(' %s' % line)
2273
2274 results = []
2275 if (prefs):
2276 results.append(output_api.PresubmitPromptWarning(
2277 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2278 'by browser sync settings. If these prefs should be controlled by OS '
2279 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2280 if (priority_prefs):
2281 results.append(output_api.PresubmitPromptWarning(
2282 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2283 'controlled by browser sync settings. If these prefs should be '
2284 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2285 'instead.\n' + '\n'.join(prefs)))
2286 return results
2287
2288
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492289# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272290def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2291 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312292 The native_client_sdk directory is excluded because it has auto-generated PNG
2293 files for documentation.
[email protected]d2530012013-01-25 16:39:272294 """
[email protected]d2530012013-01-25 16:39:272295 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492296 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042297 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312298 file_filter = lambda f: input_api.FilterSourceFile(
2299 f, white_list=white_list, black_list=black_list)
2300 for f in input_api.AffectedFiles(include_deletes=False,
2301 file_filter=file_filter):
2302 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272303
2304 results = []
2305 if errors:
2306 results.append(output_api.PresubmitError(
2307 'The name of PNG files should not have abbreviations. \n'
2308 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2309 'Contact [email protected] if you have questions.', errors))
2310 return results
2311
2312
Daniel Cheng4dcdb6b2017-04-13 08:30:172313def _ExtractAddRulesFromParsedDeps(parsed_deps):
2314 """Extract the rules that add dependencies from a parsed DEPS file.
2315
2316 Args:
2317 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2318 add_rules = set()
2319 add_rules.update([
2320 rule[1:] for rule in parsed_deps.get('include_rules', [])
2321 if rule.startswith('+') or rule.startswith('!')
2322 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502323 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172324 {}).iteritems():
2325 add_rules.update([
2326 rule[1:] for rule in rules
2327 if rule.startswith('+') or rule.startswith('!')
2328 ])
2329 return add_rules
2330
2331
2332def _ParseDeps(contents):
2333 """Simple helper for parsing DEPS files."""
2334 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172335 class _VarImpl:
2336
2337 def __init__(self, local_scope):
2338 self._local_scope = local_scope
2339
2340 def Lookup(self, var_name):
2341 """Implements the Var syntax."""
2342 try:
2343 return self._local_scope['vars'][var_name]
2344 except KeyError:
2345 raise Exception('Var is not defined: %s' % var_name)
2346
2347 local_scope = {}
2348 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172349 'Var': _VarImpl(local_scope).Lookup,
2350 }
2351 exec contents in global_scope, local_scope
2352 return local_scope
2353
2354
2355def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082356 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412357 a set of DEPS entries that we should look up.
2358
2359 For a directory (rather than a specific filename) we fake a path to
2360 a specific filename by adding /DEPS. This is chosen as a file that
2361 will seldom or never be subject to per-file include_rules.
2362 """
[email protected]2b438d62013-11-14 17:54:142363 # We ignore deps entries on auto-generated directories.
2364 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082365
Daniel Cheng4dcdb6b2017-04-13 08:30:172366 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2367 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2368
2369 added_deps = new_deps.difference(old_deps)
2370
[email protected]2b438d62013-11-14 17:54:142371 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172372 for added_dep in added_deps:
2373 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2374 continue
2375 # Assume that a rule that ends in .h is a rule for a specific file.
2376 if added_dep.endswith('.h'):
2377 results.add(added_dep)
2378 else:
2379 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082380 return results
2381
2382
[email protected]e871964c2013-05-13 14:14:552383def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2384 """When a dependency prefixed with + is added to a DEPS file, we
2385 want to make sure that the change is reviewed by an OWNER of the
2386 target file or directory, to avoid layering violations from being
2387 introduced. This check verifies that this happens.
2388 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172389 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242390
2391 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492392 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242393 for f in input_api.AffectedFiles(include_deletes=False,
2394 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552395 filename = input_api.os_path.basename(f.LocalPath())
2396 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172397 virtual_depended_on_files.update(_CalculateAddedDeps(
2398 input_api.os_path,
2399 '\n'.join(f.OldContents()),
2400 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552401
[email protected]e871964c2013-05-13 14:14:552402 if not virtual_depended_on_files:
2403 return []
2404
2405 if input_api.is_committing:
2406 if input_api.tbr:
2407 return [output_api.PresubmitNotifyResult(
2408 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272409 if input_api.dry_run:
2410 return [output_api.PresubmitNotifyResult(
2411 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552412 if not input_api.change.issue:
2413 return [output_api.PresubmitError(
2414 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402415 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552416 output = output_api.PresubmitError
2417 else:
2418 output = output_api.PresubmitNotifyResult
2419
2420 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502421 owner_email, reviewers = (
2422 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2423 input_api,
2424 owners_db.email_regexp,
2425 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552426
2427 owner_email = owner_email or input_api.change.author_email
2428
[email protected]de4f7d22013-05-23 14:27:462429 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512430 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462431 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552432 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2433 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412434
2435 # We strip the /DEPS part that was added by
2436 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2437 # directory.
2438 def StripDeps(path):
2439 start_deps = path.rfind('/DEPS')
2440 if start_deps != -1:
2441 return path[:start_deps]
2442 else:
2443 return path
2444 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552445 for path in missing_files]
2446
2447 if unapproved_dependencies:
2448 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152449 output('You need LGTM from owners of depends-on paths in DEPS that were '
2450 'modified in this CL:\n %s' %
2451 '\n '.join(sorted(unapproved_dependencies)))]
2452 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2453 output_list.append(output(
2454 'Suggested missing target path OWNERS:\n %s' %
2455 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552456 return output_list
2457
2458 return []
2459
2460
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492461# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402462def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492463 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402464 black_list = (_EXCLUDED_PATHS +
2465 _TEST_CODE_EXCLUDED_PATHS +
2466 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042467 (r"^base[\\/]logging\.h$",
2468 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222469 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042470 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2471 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2472 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122473 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182474 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152475 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032476 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152477 r"^chrome[\\/]chrome_cleaner[\\/].*",
2478 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2479 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042480 r"^chromecast[\\/]",
2481 r"^cloud_print[\\/]",
2482 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482483 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052484 r"^components[\\/]media_control[\\/]renderer[\\/]"
2485 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042486 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462487 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042488 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462489 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042490 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252491 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042492 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2493 r"^courgette[\\/]courgette_tool\.cc$",
2494 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272495 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002496 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332497 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042498 r"^ipc[\\/]ipc_logging\.cc$",
2499 r"^native_client_sdk[\\/]",
2500 r"^remoting[\\/]base[\\/]logging\.h$",
2501 r"^remoting[\\/]host[\\/].*",
2502 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062503 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332504 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042505 r"^tools[\\/]",
2506 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2507 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332508 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402509 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492510 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402511
thomasanderson625d3932017-03-29 07:16:582512 log_info = set([])
2513 printf = set([])
[email protected]85218562013-11-22 07:41:402514
2515 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582516 for _, line in f.ChangedContents():
2517 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2518 log_info.add(f.LocalPath())
2519 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2520 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372521
thomasanderson625d3932017-03-29 07:16:582522 if input_api.re.search(r"\bprintf\(", line):
2523 printf.add(f.LocalPath())
2524 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2525 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402526
2527 if log_info:
2528 return [output_api.PresubmitError(
2529 'These files spam the console log with LOG(INFO):',
2530 items=log_info)]
2531 if printf:
2532 return [output_api.PresubmitError(
2533 'These files spam the console log with printf/fprintf:',
2534 items=printf)]
2535 return []
2536
2537
[email protected]49aa76a2013-12-04 06:59:162538def _CheckForAnonymousVariables(input_api, output_api):
2539 """These types are all expected to hold locks while in scope and
2540 so should never be anonymous (which causes them to be immediately
2541 destroyed)."""
2542 they_who_must_be_named = [
2543 'base::AutoLock',
2544 'base::AutoReset',
2545 'base::AutoUnlock',
2546 'SkAutoAlphaRestore',
2547 'SkAutoBitmapShaderInstall',
2548 'SkAutoBlitterChoose',
2549 'SkAutoBounderCommit',
2550 'SkAutoCallProc',
2551 'SkAutoCanvasRestore',
2552 'SkAutoCommentBlock',
2553 'SkAutoDescriptor',
2554 'SkAutoDisableDirectionCheck',
2555 'SkAutoDisableOvalCheck',
2556 'SkAutoFree',
2557 'SkAutoGlyphCache',
2558 'SkAutoHDC',
2559 'SkAutoLockColors',
2560 'SkAutoLockPixels',
2561 'SkAutoMalloc',
2562 'SkAutoMaskFreeImage',
2563 'SkAutoMutexAcquire',
2564 'SkAutoPathBoundsUpdate',
2565 'SkAutoPDFRelease',
2566 'SkAutoRasterClipValidate',
2567 'SkAutoRef',
2568 'SkAutoTime',
2569 'SkAutoTrace',
2570 'SkAutoUnref',
2571 ]
2572 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2573 # bad: base::AutoLock(lock.get());
2574 # not bad: base::AutoLock lock(lock.get());
2575 bad_pattern = input_api.re.compile(anonymous)
2576 # good: new base::AutoLock(lock.get())
2577 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2578 errors = []
2579
2580 for f in input_api.AffectedFiles():
2581 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2582 continue
2583 for linenum, line in f.ChangedContents():
2584 if bad_pattern.search(line) and not good_pattern.search(line):
2585 errors.append('%s:%d' % (f.LocalPath(), linenum))
2586
2587 if errors:
2588 return [output_api.PresubmitError(
2589 'These lines create anonymous variables that need to be named:',
2590 items=errors)]
2591 return []
2592
2593
Peter Kasting4844e46e2018-02-23 07:27:102594def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532595 # Returns whether |template_str| is of the form <T, U...> for some types T
2596 # and U. Assumes that |template_str| is already in the form <...>.
2597 def HasMoreThanOneArg(template_str):
2598 # Level of <...> nesting.
2599 nesting = 0
2600 for c in template_str:
2601 if c == '<':
2602 nesting += 1
2603 elif c == '>':
2604 nesting -= 1
2605 elif c == ',' and nesting == 1:
2606 return True
2607 return False
2608
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492609 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102610 sources = lambda affected_file: input_api.FilterSourceFile(
2611 affected_file,
2612 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2613 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492614 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552615
2616 # Pattern to capture a single "<...>" block of template arguments. It can
2617 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2618 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2619 # latter would likely require counting that < and > match, which is not
2620 # expressible in regular languages. Should the need arise, one can introduce
2621 # limited counting (matching up to a total number of nesting depth), which
2622 # should cover all practical cases for already a low nesting limit.
2623 template_arg_pattern = (
2624 r'<[^>]*' # Opening block of <.
2625 r'>([^<]*>)?') # Closing block of >.
2626 # Prefix expressing that whatever follows is not already inside a <...>
2627 # block.
2628 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102629 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552630 not_inside_template_arg_pattern
2631 + r'\bstd::unique_ptr'
2632 + template_arg_pattern
2633 + r'\(\)')
2634
2635 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2636 template_arg_no_array_pattern = (
2637 r'<[^>]*[^]]' # Opening block of <.
2638 r'>([^(<]*[^]]>)?') # Closing block of >.
2639 # Prefix saying that what follows is the start of an expression.
2640 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2641 # Suffix saying that what follows are call parentheses with a non-empty list
2642 # of arguments.
2643 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532644 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552645 return_construct_pattern = input_api.re.compile(
2646 start_of_expr_pattern
2647 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532648 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552649 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532650 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552651 + nonempty_arg_list_pattern)
2652
Vaclav Brozek851d9602018-04-04 16:13:052653 problems_constructor = []
2654 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102655 for f in input_api.AffectedSourceFiles(sources):
2656 for line_number, line in f.ChangedContents():
2657 # Disallow:
2658 # return std::unique_ptr<T>(foo);
2659 # bar = std::unique_ptr<T>(foo);
2660 # But allow:
2661 # return std::unique_ptr<T[]>(foo);
2662 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532663 # And also allow cases when the second template argument is present. Those
2664 # cases cannot be handled by std::make_unique:
2665 # return std::unique_ptr<T, U>(foo);
2666 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052667 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532668 return_construct_result = return_construct_pattern.search(line)
2669 if return_construct_result and not HasMoreThanOneArg(
2670 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052671 problems_constructor.append(
2672 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102673 # Disallow:
2674 # std::unique_ptr<T>()
2675 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052676 problems_nullptr.append(
2677 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2678
2679 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162680 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052681 errors.append(output_api.PresubmitError(
2682 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162683 problems_nullptr))
2684 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052685 errors.append(output_api.PresubmitError(
2686 'The following files use explicit std::unique_ptr constructor.'
2687 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162688 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102689 return errors
2690
2691
[email protected]999261d2014-03-03 20:08:082692def _CheckUserActionUpdate(input_api, output_api):
2693 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522694 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082695 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522696 # If actions.xml is already included in the changelist, the PRESUBMIT
2697 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082698 return []
2699
[email protected]999261d2014-03-03 20:08:082700 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2701 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522702 current_actions = None
[email protected]999261d2014-03-03 20:08:082703 for f in input_api.AffectedFiles(file_filter=file_filter):
2704 for line_num, line in f.ChangedContents():
2705 match = input_api.re.search(action_re, line)
2706 if match:
[email protected]2f92dec2014-03-07 19:21:522707 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2708 # loaded only once.
2709 if not current_actions:
2710 with open('tools/metrics/actions/actions.xml') as actions_f:
2711 current_actions = actions_f.read()
2712 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082713 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522714 action = 'name="{0}"'.format(action_name)
2715 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082716 return [output_api.PresubmitPromptWarning(
2717 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522718 'tools/metrics/actions/actions.xml. Please run '
2719 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082720 % (f.LocalPath(), line_num, action_name))]
2721 return []
2722
2723
Daniel Cheng13ca61a882017-08-25 15:11:252724def _ImportJSONCommentEater(input_api):
2725 import sys
2726 sys.path = sys.path + [input_api.os_path.join(
2727 input_api.PresubmitLocalPath(),
2728 'tools', 'json_comment_eater')]
2729 import json_comment_eater
2730 return json_comment_eater
2731
2732
[email protected]99171a92014-06-03 08:44:472733def _GetJSONParseError(input_api, filename, eat_comments=True):
2734 try:
2735 contents = input_api.ReadFile(filename)
2736 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252737 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132738 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472739
2740 input_api.json.loads(contents)
2741 except ValueError as e:
2742 return e
2743 return None
2744
2745
2746def _GetIDLParseError(input_api, filename):
2747 try:
2748 contents = input_api.ReadFile(filename)
2749 idl_schema = input_api.os_path.join(
2750 input_api.PresubmitLocalPath(),
2751 'tools', 'json_schema_compiler', 'idl_schema.py')
2752 process = input_api.subprocess.Popen(
2753 [input_api.python_executable, idl_schema],
2754 stdin=input_api.subprocess.PIPE,
2755 stdout=input_api.subprocess.PIPE,
2756 stderr=input_api.subprocess.PIPE,
2757 universal_newlines=True)
2758 (_, error) = process.communicate(input=contents)
2759 return error or None
2760 except ValueError as e:
2761 return e
2762
2763
2764def _CheckParseErrors(input_api, output_api):
2765 """Check that IDL and JSON files do not contain syntax errors."""
2766 actions = {
2767 '.idl': _GetIDLParseError,
2768 '.json': _GetJSONParseError,
2769 }
[email protected]99171a92014-06-03 08:44:472770 # Most JSON files are preprocessed and support comments, but these do not.
2771 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042772 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472773 ]
2774 # Only run IDL checker on files in these directories.
2775 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042776 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2777 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472778 ]
2779
2780 def get_action(affected_file):
2781 filename = affected_file.LocalPath()
2782 return actions.get(input_api.os_path.splitext(filename)[1])
2783
[email protected]99171a92014-06-03 08:44:472784 def FilterFile(affected_file):
2785 action = get_action(affected_file)
2786 if not action:
2787 return False
2788 path = affected_file.LocalPath()
2789
Erik Staab2dd72b12020-04-16 15:03:402790 if _MatchesFile(input_api,
2791 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2792 path):
[email protected]99171a92014-06-03 08:44:472793 return False
2794
2795 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162796 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472797 return False
2798 return True
2799
2800 results = []
2801 for affected_file in input_api.AffectedFiles(
2802 file_filter=FilterFile, include_deletes=False):
2803 action = get_action(affected_file)
2804 kwargs = {}
2805 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162806 _MatchesFile(input_api, json_no_comments_patterns,
2807 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472808 kwargs['eat_comments'] = False
2809 parse_error = action(input_api,
2810 affected_file.AbsoluteLocalPath(),
2811 **kwargs)
2812 if parse_error:
2813 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2814 (affected_file.LocalPath(), parse_error)))
2815 return results
2816
2817
[email protected]760deea2013-12-10 19:33:492818def _CheckJavaStyle(input_api, output_api):
2819 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472820 import sys
[email protected]760deea2013-12-10 19:33:492821 original_sys_path = sys.path
2822 try:
2823 sys.path = sys.path + [input_api.os_path.join(
2824 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2825 import checkstyle
2826 finally:
2827 # Restore sys.path to what it was before.
2828 sys.path = original_sys_path
2829
2830 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092831 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512832 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492833
2834
Nate Fischerdfd9812e2019-07-18 22:03:002835def _CheckPythonDevilInit(input_api, output_api):
2836 """Checks to make sure devil is initialized correctly in python scripts."""
2837 script_common_initialize_pattern = input_api.re.compile(
2838 r'script_common\.InitializeEnvironment\(')
2839 devil_env_config_initialize = input_api.re.compile(
2840 r'devil_env\.config\.Initialize\(')
2841
2842 errors = []
2843
2844 sources = lambda affected_file: input_api.FilterSourceFile(
2845 affected_file,
2846 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2847 (r'^build[\\/]android[\\/]devil_chromium\.py',
2848 r'^third_party[\\/].*',)),
2849 white_list=[r'.*\.py$'])
2850
2851 for f in input_api.AffectedSourceFiles(sources):
2852 for line_num, line in f.ChangedContents():
2853 if (script_common_initialize_pattern.search(line) or
2854 devil_env_config_initialize.search(line)):
2855 errors.append("%s:%d" % (f.LocalPath(), line_num))
2856
2857 results = []
2858
2859 if errors:
2860 results.append(output_api.PresubmitError(
2861 'Devil initialization should always be done using '
2862 'devil_chromium.Initialize() in the chromium project, to use better '
2863 'defaults for dependencies (ex. up-to-date version of adb).',
2864 errors))
2865
2866 return results
2867
2868
Sean Kau46e29bc2017-08-28 16:31:162869def _MatchesFile(input_api, patterns, path):
2870 for pattern in patterns:
2871 if input_api.re.search(pattern, path):
2872 return True
2873 return False
2874
2875
Daniel Cheng7052cdf2017-11-21 19:23:292876def _GetOwnersFilesToCheckForIpcOwners(input_api):
2877 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172878
Daniel Cheng7052cdf2017-11-21 19:23:292879 Returns:
2880 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2881 contain to cover IPC-related files with noparent reviewer rules.
2882 """
2883 # Whether or not a file affects IPC is (mostly) determined by a simple list
2884 # of filename patterns.
dchenge07de812016-06-20 19:27:172885 file_patterns = [
palmerb19a0932017-01-24 04:00:312886 # Legacy IPC:
dchenge07de812016-06-20 19:27:172887 '*_messages.cc',
2888 '*_messages*.h',
2889 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312890 # Mojo IPC:
dchenge07de812016-06-20 19:27:172891 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472892 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172893 '*_struct_traits*.*',
2894 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312895 '*.typemap',
2896 # Android native IPC:
2897 '*.aidl',
2898 # Blink uses a different file naming convention:
2899 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472900 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172901 '*StructTraits*.*',
2902 '*TypeConverter*.*',
2903 ]
2904
scottmg7a6ed5ba2016-11-04 18:22:042905 # These third_party directories do not contain IPCs, but contain files
2906 # matching the above patterns, which trigger false positives.
2907 exclude_paths = [
2908 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162909 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232910 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292911 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542912 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162913 # These files are just used to communicate between class loaders running
2914 # in the same process.
2915 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572916 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2917
scottmg7a6ed5ba2016-11-04 18:22:042918 ]
2919
dchenge07de812016-06-20 19:27:172920 # Dictionary mapping an OWNERS file path to Patterns.
2921 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2922 # rules ) to a PatternEntry.
2923 # PatternEntry is a dictionary with two keys:
2924 # - 'files': the files that are matched by this pattern
2925 # - 'rules': the per-file rules needed for this pattern
2926 # For example, if we expect OWNERS file to contain rules for *.mojom and
2927 # *_struct_traits*.*, Patterns might look like this:
2928 # {
2929 # '*.mojom': {
2930 # 'files': ...,
2931 # 'rules': [
2932 # 'per-file *.mojom=set noparent',
2933 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2934 # ],
2935 # },
2936 # '*_struct_traits*.*': {
2937 # 'files': ...,
2938 # 'rules': [
2939 # 'per-file *_struct_traits*.*=set noparent',
2940 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2941 # ],
2942 # },
2943 # }
2944 to_check = {}
2945
Daniel Cheng13ca61a882017-08-25 15:11:252946 def AddPatternToCheck(input_file, pattern):
2947 owners_file = input_api.os_path.join(
2948 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2949 if owners_file not in to_check:
2950 to_check[owners_file] = {}
2951 if pattern not in to_check[owners_file]:
2952 to_check[owners_file][pattern] = {
2953 'files': [],
2954 'rules': [
2955 'per-file %s=set noparent' % pattern,
2956 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2957 ]
2958 }
Vaclav Brozekd5de76a2018-03-17 07:57:502959 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252960
dchenge07de812016-06-20 19:27:172961 # Iterate through the affected files to see what we actually need to check
2962 # for. We should only nag patch authors about per-file rules if a file in that
2963 # directory would match that pattern. If a directory only contains *.mojom
2964 # files and no *_messages*.h files, we should only nag about rules for
2965 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252966 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262967 # Manifest files don't have a strong naming convention. Instead, try to find
2968 # affected .cc and .h files which look like they contain a manifest
2969 # definition.
2970 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2971 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2972 if (manifest_pattern.search(f.LocalPath()) and not
2973 test_manifest_pattern.search(f.LocalPath())):
2974 # We expect all actual service manifest files to contain at least one
2975 # qualified reference to service_manager::Manifest.
2976 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252977 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172978 for pattern in file_patterns:
2979 if input_api.fnmatch.fnmatch(
2980 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042981 skip = False
2982 for exclude in exclude_paths:
2983 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2984 skip = True
2985 break
2986 if skip:
2987 continue
Daniel Cheng13ca61a882017-08-25 15:11:252988 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172989 break
2990
Daniel Cheng7052cdf2017-11-21 19:23:292991 return to_check
2992
2993
Wez17c66962020-04-29 15:26:032994def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2995 """Adds OWNERS files to check for correct Fuchsia security owners."""
2996
2997 file_patterns = [
2998 # Component specifications.
2999 '*.cml', # Component Framework v2.
3000 '*.cmx', # Component Framework v1.
3001
3002 # Fuchsia IDL protocol specifications.
3003 '*.fidl',
3004 ]
3005
3006 def AddPatternToCheck(input_file, pattern):
3007 owners_file = input_api.os_path.join(
3008 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3009 if owners_file not in to_check:
3010 to_check[owners_file] = {}
3011 if pattern not in to_check[owners_file]:
3012 to_check[owners_file][pattern] = {
3013 'files': [],
3014 'rules': [
3015 'per-file %s=set noparent' % pattern,
3016 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3017 ]
3018 }
3019 to_check[owners_file][pattern]['files'].append(input_file)
3020
3021 # Iterate through the affected files to see what we actually need to check
3022 # for. We should only nag patch authors about per-file rules if a file in that
3023 # directory would match that pattern.
3024 for f in input_api.AffectedFiles(include_deletes=False):
3025 for pattern in file_patterns:
3026 if input_api.fnmatch.fnmatch(
3027 input_api.os_path.basename(f.LocalPath()), pattern):
3028 AddPatternToCheck(f, pattern)
3029 break
3030
3031 return to_check
3032
3033
3034def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293035 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3036 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033037 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293038
3039 if to_check:
3040 # If there are any OWNERS files to check, there are IPC-related changes in
3041 # this CL. Auto-CC the review list.
3042 output_api.AppendCC('[email protected]')
3043
3044 # Go through the OWNERS files to check, filtering out rules that are already
3045 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173046 for owners_file, patterns in to_check.iteritems():
3047 try:
3048 with file(owners_file) as f:
3049 lines = set(f.read().splitlines())
3050 for entry in patterns.itervalues():
3051 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3052 ]
3053 except IOError:
3054 # No OWNERS file, so all the rules are definitely missing.
3055 continue
3056
3057 # All the remaining lines weren't found in OWNERS files, so emit an error.
3058 errors = []
3059 for owners_file, patterns in to_check.iteritems():
3060 missing_lines = []
3061 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503062 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173063 missing_lines.extend(entry['rules'])
3064 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3065 if missing_lines:
3066 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053067 'Because of the presence of files:\n%s\n\n'
3068 '%s needs the following %d lines added:\n\n%s' %
3069 ('\n'.join(files), owners_file, len(missing_lines),
3070 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173071
3072 results = []
3073 if errors:
vabrf5ce3bf92016-07-11 14:52:413074 if input_api.is_committing:
3075 output = output_api.PresubmitError
3076 else:
3077 output = output_api.PresubmitPromptWarning
3078 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593079 'Found OWNERS files that need to be updated for IPC security ' +
3080 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173081 long_text='\n\n'.join(errors)))
3082
3083 return results
3084
3085
Robert Sesek2c905332020-05-06 23:17:133086def _GetFilesUsingSecurityCriticalFunctions(input_api):
3087 """Checks affected files for changes to security-critical calls. This
3088 function checks the full change diff, to catch both additions/changes
3089 and removals.
3090
3091 Returns a dict keyed by file name, and the value is a set of detected
3092 functions.
3093 """
3094 # Map of function pretty name (displayed in an error) to the pattern to
3095 # match it with.
3096 _PATTERNS_TO_CHECK = {
3097 'content::ServiceProcessHost::LaunchOptions::WithSandboxType':
3098 'WithSandboxType\\('
3099 }
3100 _PATTERNS_TO_CHECK = {
3101 k: input_api.re.compile(v)
3102 for k, v in _PATTERNS_TO_CHECK.items()
3103 }
3104
3105 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3106 files_to_functions = {}
3107 for f in input_api.AffectedFiles():
3108 diff = f.GenerateScmDiff()
3109 for line in diff.split('\n'):
3110 # Not using just RightHandSideLines() because removing a
3111 # call to a security-critical function can be just as important
3112 # as adding or changing the arguments.
3113 if line.startswith('-') or (line.startswith('+') and
3114 not line.startswith('++')):
3115 for name, pattern in _PATTERNS_TO_CHECK.items():
3116 if pattern.search(line):
3117 path = f.LocalPath()
3118 if not path in files_to_functions:
3119 files_to_functions[path] = set()
3120 files_to_functions[path].add(name)
3121 return files_to_functions
3122
3123
3124def _CheckSecurityChanges(input_api, output_api):
3125 """Checks that changes involving security-critical functions are reviewed
3126 by the security team.
3127 """
3128 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3129 if len(files_to_functions):
3130 owners_db = input_api.owners_db
3131 owner_email, reviewers = (
3132 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3133 input_api,
3134 owners_db.email_regexp,
3135 approval_needed=input_api.is_committing))
3136
3137 # Load the OWNERS file for security changes.
3138 owners_file = 'ipc/SECURITY_OWNERS'
3139 security_owners = owners_db.owners_rooted_at_file(owners_file)
3140
3141 has_security_owner = any([owner in reviewers for owner in security_owners])
3142 if not has_security_owner:
3143 msg = 'The following files change calls to security-sensive functions\n' \
3144 'that need to be reviewed by {}.\n'.format(owners_file)
3145 for path, names in files_to_functions.items():
3146 msg += ' {}\n'.format(path)
3147 for name in names:
3148 msg += ' {}\n'.format(name)
3149 msg += '\n'
3150
3151 if input_api.is_committing:
3152 output = output_api.PresubmitError
3153 else:
3154 output = output_api.PresubmitNotifyResult
3155 return [output(msg)]
3156
3157 return []
3158
3159
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263160def _CheckSetNoParent(input_api, output_api):
3161 """Checks that set noparent is only used together with an OWNERS file in
3162 //build/OWNERS.setnoparent (see also
3163 //docs/code_reviews.md#owners-files-details)
3164 """
3165 errors = []
3166
3167 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3168 allowed_owners_files = set()
3169 with open(allowed_owners_files_file, 'r') as f:
3170 for line in f:
3171 line = line.strip()
3172 if not line or line.startswith('#'):
3173 continue
3174 allowed_owners_files.add(line)
3175
3176 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3177
3178 for f in input_api.AffectedFiles(include_deletes=False):
3179 if not f.LocalPath().endswith('OWNERS'):
3180 continue
3181
3182 found_owners_files = set()
3183 found_set_noparent_lines = dict()
3184
3185 # Parse the OWNERS file.
3186 for lineno, line in enumerate(f.NewContents(), 1):
3187 line = line.strip()
3188 if line.startswith('set noparent'):
3189 found_set_noparent_lines[''] = lineno
3190 if line.startswith('file://'):
3191 if line in allowed_owners_files:
3192 found_owners_files.add('')
3193 if line.startswith('per-file'):
3194 match = per_file_pattern.match(line)
3195 if match:
3196 glob = match.group(1).strip()
3197 directive = match.group(2).strip()
3198 if directive == 'set noparent':
3199 found_set_noparent_lines[glob] = lineno
3200 if directive.startswith('file://'):
3201 if directive in allowed_owners_files:
3202 found_owners_files.add(glob)
3203
3204 # Check that every set noparent line has a corresponding file:// line
3205 # listed in build/OWNERS.setnoparent.
3206 for set_noparent_line in found_set_noparent_lines:
3207 if set_noparent_line in found_owners_files:
3208 continue
3209 errors.append(' %s:%d' % (f.LocalPath(),
3210 found_set_noparent_lines[set_noparent_line]))
3211
3212 results = []
3213 if errors:
3214 if input_api.is_committing:
3215 output = output_api.PresubmitError
3216 else:
3217 output = output_api.PresubmitPromptWarning
3218 results.append(output(
3219 'Found the following "set noparent" restrictions in OWNERS files that '
3220 'do not include owners from build/OWNERS.setnoparent:',
3221 long_text='\n\n'.join(errors)))
3222 return results
3223
3224
jbriance9e12f162016-11-25 07:57:503225def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313226 """Checks that added or removed lines in non third party affected
3227 header files do not lead to new useless class or struct forward
3228 declaration.
jbriance9e12f162016-11-25 07:57:503229 """
3230 results = []
3231 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3232 input_api.re.MULTILINE)
3233 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3234 input_api.re.MULTILINE)
3235 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313236 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193237 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493238 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313239 continue
3240
jbriance9e12f162016-11-25 07:57:503241 if not f.LocalPath().endswith('.h'):
3242 continue
3243
3244 contents = input_api.ReadFile(f)
3245 fwd_decls = input_api.re.findall(class_pattern, contents)
3246 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3247
3248 useless_fwd_decls = []
3249 for decl in fwd_decls:
3250 count = sum(1 for _ in input_api.re.finditer(
3251 r'\b%s\b' % input_api.re.escape(decl), contents))
3252 if count == 1:
3253 useless_fwd_decls.append(decl)
3254
3255 if not useless_fwd_decls:
3256 continue
3257
3258 for line in f.GenerateScmDiff().splitlines():
3259 if (line.startswith('-') and not line.startswith('--') or
3260 line.startswith('+') and not line.startswith('++')):
3261 for decl in useless_fwd_decls:
3262 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3263 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243264 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503265 (f.LocalPath(), decl)))
3266 useless_fwd_decls.remove(decl)
3267
3268 return results
3269
Jinsong Fan91ebbbd2019-04-16 14:57:173270def _CheckAndroidDebuggableBuild(input_api, output_api):
3271 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3272 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3273 this is a debuggable build of Android.
3274 """
3275 build_type_check_pattern = input_api.re.compile(
3276 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3277
3278 errors = []
3279
3280 sources = lambda affected_file: input_api.FilterSourceFile(
3281 affected_file,
3282 black_list=(_EXCLUDED_PATHS +
3283 _TEST_CODE_EXCLUDED_PATHS +
3284 input_api.DEFAULT_BLACK_LIST +
3285 (r"^android_webview[\\/]support_library[\\/]"
3286 "boundary_interfaces[\\/]",
3287 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3288 r'^third_party[\\/].*',
3289 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3290 r"webview[\\/]chromium[\\/]License.*",)),
3291 white_list=[r'.*\.java$'])
3292
3293 for f in input_api.AffectedSourceFiles(sources):
3294 for line_num, line in f.ChangedContents():
3295 if build_type_check_pattern.search(line):
3296 errors.append("%s:%d" % (f.LocalPath(), line_num))
3297
3298 results = []
3299
3300 if errors:
3301 results.append(output_api.PresubmitPromptWarning(
3302 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3303 ' Please use BuildInfo.isDebugAndroid() instead.',
3304 errors))
3305
3306 return results
jbriance9e12f162016-11-25 07:57:503307
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493308# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293309def _CheckAndroidToastUsage(input_api, output_api):
3310 """Checks that code uses org.chromium.ui.widget.Toast instead of
3311 android.widget.Toast (Chromium Toast doesn't force hardware
3312 acceleration on low-end devices, saving memory).
3313 """
3314 toast_import_pattern = input_api.re.compile(
3315 r'^import android\.widget\.Toast;$')
3316
3317 errors = []
3318
3319 sources = lambda affected_file: input_api.FilterSourceFile(
3320 affected_file,
3321 black_list=(_EXCLUDED_PATHS +
3322 _TEST_CODE_EXCLUDED_PATHS +
3323 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043324 (r'^chromecast[\\/].*',
3325 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493326 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293327
3328 for f in input_api.AffectedSourceFiles(sources):
3329 for line_num, line in f.ChangedContents():
3330 if toast_import_pattern.search(line):
3331 errors.append("%s:%d" % (f.LocalPath(), line_num))
3332
3333 results = []
3334
3335 if errors:
3336 results.append(output_api.PresubmitError(
3337 'android.widget.Toast usage is detected. Android toasts use hardware'
3338 ' acceleration, and can be\ncostly on low-end devices. Please use'
3339 ' org.chromium.ui.widget.Toast instead.\n'
3340 'Contact [email protected] if you have any questions.',
3341 errors))
3342
3343 return results
3344
3345
dgnaa68d5e2015-06-10 10:08:223346def _CheckAndroidCrLogUsage(input_api, output_api):
3347 """Checks that new logs using org.chromium.base.Log:
3348 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513349 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223350 """
pkotwicza1dd0b002016-05-16 14:41:043351
torne89540622017-03-24 19:41:303352 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043353 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303354 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043355 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303356 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043357 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3358 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093359 # The customtabs_benchmark is a small app that does not depend on Chromium
3360 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043361 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043362 ]
3363
dgnaa68d5e2015-06-10 10:08:223364 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123365 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3366 class_in_base_pattern = input_api.re.compile(
3367 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3368 has_some_log_import_pattern = input_api.re.compile(
3369 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223370 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553371 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223372 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463373 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553374 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223375
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463376 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493377 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043378 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123379
dgnaa68d5e2015-06-10 10:08:223380 tag_decl_errors = []
3381 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123382 tag_errors = []
dgn38736db2015-09-18 19:20:513383 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123384 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223385
3386 for f in input_api.AffectedSourceFiles(sources):
3387 file_content = input_api.ReadFile(f)
3388 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223389 # Per line checks
dgn87d9fb62015-06-12 09:15:123390 if (cr_log_import_pattern.search(file_content) or
3391 (class_in_base_pattern.search(file_content) and
3392 not has_some_log_import_pattern.search(file_content))):
3393 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223394 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553395 if rough_log_decl_pattern.search(line):
3396 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223397
3398 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123399 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223400 if match:
3401 has_modified_logs = True
3402
3403 # Make sure it uses "TAG"
3404 if not match.group('tag') == 'TAG':
3405 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123406 else:
3407 # Report non cr Log function calls in changed lines
3408 for line_num, line in f.ChangedContents():
3409 if log_call_pattern.search(line):
3410 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223411
3412 # Per file checks
3413 if has_modified_logs:
3414 # Make sure the tag is using the "cr" prefix and is not too long
3415 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513416 tag_name = match.group('name') if match else None
3417 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223418 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513419 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223420 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513421 elif '.' in tag_name:
3422 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223423
3424 results = []
3425 if tag_decl_errors:
3426 results.append(output_api.PresubmitPromptWarning(
3427 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513428 '"private static final String TAG = "<package tag>".\n'
3429 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223430 tag_decl_errors))
3431
3432 if tag_length_errors:
3433 results.append(output_api.PresubmitError(
3434 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513435 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223436 tag_length_errors))
3437
3438 if tag_errors:
3439 results.append(output_api.PresubmitPromptWarning(
3440 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3441 tag_errors))
3442
dgn87d9fb62015-06-12 09:15:123443 if util_log_errors:
dgn4401aa52015-04-29 16:26:173444 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123445 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3446 util_log_errors))
3447
dgn38736db2015-09-18 19:20:513448 if tag_with_dot_errors:
3449 results.append(output_api.PresubmitPromptWarning(
3450 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3451 tag_with_dot_errors))
3452
dgn4401aa52015-04-29 16:26:173453 return results
3454
3455
Yoland Yanb92fa522017-08-28 17:37:063456def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3457 """Checks that junit.framework.* is no longer used."""
3458 deprecated_junit_framework_pattern = input_api.re.compile(
3459 r'^import junit\.framework\..*;',
3460 input_api.re.MULTILINE)
3461 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493462 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063463 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133464 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063465 for line_num, line in f.ChangedContents():
3466 if deprecated_junit_framework_pattern.search(line):
3467 errors.append("%s:%d" % (f.LocalPath(), line_num))
3468
3469 results = []
3470 if errors:
3471 results.append(output_api.PresubmitError(
3472 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3473 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3474 ' if you have any question.', errors))
3475 return results
3476
3477
3478def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3479 """Checks that if new Java test classes have inheritance.
3480 Either the new test class is JUnit3 test or it is a JUnit4 test class
3481 with a base class, either case is undesirable.
3482 """
3483 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3484
3485 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493486 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063487 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133488 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063489 if not f.OldContents():
3490 class_declaration_start_flag = False
3491 for line_num, line in f.ChangedContents():
3492 if class_declaration_pattern.search(line):
3493 class_declaration_start_flag = True
3494 if class_declaration_start_flag and ' extends ' in line:
3495 errors.append('%s:%d' % (f.LocalPath(), line_num))
3496 if '{' in line:
3497 class_declaration_start_flag = False
3498
3499 results = []
3500 if errors:
3501 results.append(output_api.PresubmitPromptWarning(
3502 'The newly created files include Test classes that inherits from base'
3503 ' class. Please do not use inheritance in JUnit4 tests or add new'
3504 ' JUnit3 tests. Contact [email protected] if you have any'
3505 ' questions.', errors))
3506 return results
3507
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203508
yolandyan45001472016-12-21 21:12:423509def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3510 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3511 deprecated_annotation_import_pattern = input_api.re.compile(
3512 r'^import android\.test\.suitebuilder\.annotation\..*;',
3513 input_api.re.MULTILINE)
3514 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493515 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423516 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133517 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423518 for line_num, line in f.ChangedContents():
3519 if deprecated_annotation_import_pattern.search(line):
3520 errors.append("%s:%d" % (f.LocalPath(), line_num))
3521
3522 results = []
3523 if errors:
3524 results.append(output_api.PresubmitError(
3525 'Annotations in android.test.suitebuilder.annotation have been'
3526 ' deprecated since API level 24. Please use android.support.test.filters'
3527 ' from //third_party/android_support_test_runner:runner_java instead.'
3528 ' Contact [email protected] if you have any questions.', errors))
3529 return results
3530
3531
agrieve7b6479d82015-10-07 14:24:223532def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3533 """Checks if MDPI assets are placed in a correct directory."""
3534 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3535 ('/res/drawable/' in f.LocalPath() or
3536 '/res/drawable-ldrtl/' in f.LocalPath()))
3537 errors = []
3538 for f in input_api.AffectedFiles(include_deletes=False,
3539 file_filter=file_filter):
3540 errors.append(' %s' % f.LocalPath())
3541
3542 results = []
3543 if errors:
3544 results.append(output_api.PresubmitError(
3545 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3546 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3547 '/res/drawable-ldrtl/.\n'
3548 'Contact [email protected] if you have questions.', errors))
3549 return results
3550
3551
Nate Fischer535972b2017-09-16 01:06:183552def _CheckAndroidWebkitImports(input_api, output_api):
3553 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353554 android.webview.ValueCallback except in the WebView glue layer
3555 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183556 """
3557 valuecallback_import_pattern = input_api.re.compile(
3558 r'^import android\.webkit\.ValueCallback;$')
3559
3560 errors = []
3561
3562 sources = lambda affected_file: input_api.FilterSourceFile(
3563 affected_file,
3564 black_list=(_EXCLUDED_PATHS +
3565 _TEST_CODE_EXCLUDED_PATHS +
3566 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353567 (r'^android_webview[\\/]glue[\\/].*',
3568 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493569 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183570
3571 for f in input_api.AffectedSourceFiles(sources):
3572 for line_num, line in f.ChangedContents():
3573 if valuecallback_import_pattern.search(line):
3574 errors.append("%s:%d" % (f.LocalPath(), line_num))
3575
3576 results = []
3577
3578 if errors:
3579 results.append(output_api.PresubmitError(
3580 'android.webkit.ValueCallback usage is detected outside of the glue'
3581 ' layer. To stay compatible with the support library, android.webkit.*'
3582 ' classes should only be used inside the glue layer and'
3583 ' org.chromium.base.Callback should be used instead.',
3584 errors))
3585
3586 return results
3587
3588
Becky Zhou7c69b50992018-12-10 19:37:573589def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3590 """Checks Android XML styles """
3591 import sys
3592 original_sys_path = sys.path
3593 try:
3594 sys.path = sys.path + [input_api.os_path.join(
3595 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3596 import checkxmlstyle
3597 finally:
3598 # Restore sys.path to what it was before.
3599 sys.path = original_sys_path
3600
3601 if is_check_on_upload:
3602 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3603 else:
3604 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3605
3606
agrievef32bcc72016-04-04 14:57:403607class PydepsChecker(object):
3608 def __init__(self, input_api, pydeps_files):
3609 self._file_cache = {}
3610 self._input_api = input_api
3611 self._pydeps_files = pydeps_files
3612
3613 def _LoadFile(self, path):
3614 """Returns the list of paths within a .pydeps file relative to //."""
3615 if path not in self._file_cache:
3616 with open(path) as f:
3617 self._file_cache[path] = f.read()
3618 return self._file_cache[path]
3619
3620 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3621 """Returns an interable of paths within the .pydep, relativized to //."""
3622 os_path = self._input_api.os_path
3623 pydeps_dir = os_path.dirname(pydeps_path)
3624 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3625 if not l.startswith('*'))
3626 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3627
3628 def _CreateFilesToPydepsMap(self):
3629 """Returns a map of local_path -> list_of_pydeps."""
3630 ret = {}
3631 for pydep_local_path in self._pydeps_files:
3632 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3633 ret.setdefault(path, []).append(pydep_local_path)
3634 return ret
3635
3636 def ComputeAffectedPydeps(self):
3637 """Returns an iterable of .pydeps files that might need regenerating."""
3638 affected_pydeps = set()
3639 file_to_pydeps_map = None
3640 for f in self._input_api.AffectedFiles(include_deletes=True):
3641 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463642 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3643 # subrepositories. We can't figure out which files change, so re-check
3644 # all files.
3645 # Changes to print_python_deps.py affect all .pydeps.
3646 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403647 return self._pydeps_files
3648 elif local_path.endswith('.pydeps'):
3649 if local_path in self._pydeps_files:
3650 affected_pydeps.add(local_path)
3651 elif local_path.endswith('.py'):
3652 if file_to_pydeps_map is None:
3653 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3654 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3655 return affected_pydeps
3656
3657 def DetermineIfStale(self, pydeps_path):
3658 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413659 import difflib
John Budorick47ca3fe2018-02-10 00:53:103660 import os
3661
agrievef32bcc72016-04-04 14:57:403662 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3663 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103664 env = dict(os.environ)
3665 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403666 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103667 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413668 old_contents = old_pydeps_data[2:]
3669 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403670 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413671 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403672
3673
Tibor Goldschwendt360793f72019-06-25 18:23:493674def _ParseGclientArgs():
3675 args = {}
3676 with open('build/config/gclient_args.gni', 'r') as f:
3677 for line in f:
3678 line = line.strip()
3679 if not line or line.startswith('#'):
3680 continue
3681 attribute, value = line.split('=')
3682 args[attribute.strip()] = value.strip()
3683 return args
3684
3685
agrievef32bcc72016-04-04 14:57:403686def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3687 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403688 # This check is for Python dependency lists (.pydeps files), and involves
3689 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3690 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283691 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003692 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493693 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403694 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3695 results = []
3696 # First, check for new / deleted .pydeps.
3697 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033698 # Check whether we are running the presubmit check for a file in src.
3699 # f.LocalPath is relative to repo (src, or internal repo).
3700 # os_path.exists is relative to src repo.
3701 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3702 # to src and we can conclude that the pydeps is in src.
3703 if input_api.os_path.exists(f.LocalPath()):
3704 if f.LocalPath().endswith('.pydeps'):
3705 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3706 results.append(output_api.PresubmitError(
3707 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3708 'remove %s' % f.LocalPath()))
3709 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3710 results.append(output_api.PresubmitError(
3711 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3712 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403713
3714 if results:
3715 return results
3716
3717 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3718
3719 for pydep_path in checker.ComputeAffectedPydeps():
3720 try:
phajdan.jr0d9878552016-11-04 10:49:413721 result = checker.DetermineIfStale(pydep_path)
3722 if result:
3723 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403724 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413725 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3726 'To regenerate, run:\n\n %s' %
3727 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403728 except input_api.subprocess.CalledProcessError as error:
3729 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3730 long_text=error.output)]
3731
3732 return results
3733
3734
glidere61efad2015-02-18 17:39:433735def _CheckSingletonInHeaders(input_api, output_api):
3736 """Checks to make sure no header files have |Singleton<|."""
3737 def FileFilter(affected_file):
3738 # It's ok for base/memory/singleton.h to have |Singleton<|.
3739 black_list = (_EXCLUDED_PATHS +
3740 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043741 (r"^base[\\/]memory[\\/]singleton\.h$",
3742 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473743 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433744 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3745
sergeyu34d21222015-09-16 00:11:443746 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433747 files = []
3748 for f in input_api.AffectedSourceFiles(FileFilter):
3749 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3750 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3751 contents = input_api.ReadFile(f)
3752 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243753 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433754 pattern.search(line)):
3755 files.append(f)
3756 break
3757
3758 if files:
yolandyandaabc6d2016-04-18 18:29:393759 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443760 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433761 'Please move them to an appropriate source file so that the ' +
3762 'template gets instantiated in a single compilation unit.',
3763 files) ]
3764 return []
3765
3766
[email protected]fd20b902014-05-09 02:14:533767_DEPRECATED_CSS = [
3768 # Values
3769 ( "-webkit-box", "flex" ),
3770 ( "-webkit-inline-box", "inline-flex" ),
3771 ( "-webkit-flex", "flex" ),
3772 ( "-webkit-inline-flex", "inline-flex" ),
3773 ( "-webkit-min-content", "min-content" ),
3774 ( "-webkit-max-content", "max-content" ),
3775
3776 # Properties
3777 ( "-webkit-background-clip", "background-clip" ),
3778 ( "-webkit-background-origin", "background-origin" ),
3779 ( "-webkit-background-size", "background-size" ),
3780 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443781 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533782
3783 # Functions
3784 ( "-webkit-gradient", "gradient" ),
3785 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3786 ( "-webkit-linear-gradient", "linear-gradient" ),
3787 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3788 ( "-webkit-radial-gradient", "radial-gradient" ),
3789 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3790]
3791
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203792
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493793# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243794def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533795 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253796 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343797 documentation and iOS CSS for dom distiller
3798 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253799 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533800 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493801 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253802 black_list = (_EXCLUDED_PATHS +
3803 _TEST_CODE_EXCLUDED_PATHS +
3804 input_api.DEFAULT_BLACK_LIST +
3805 (r"^chrome/common/extensions/docs",
3806 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343807 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443808 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253809 r"^native_client_sdk"))
3810 file_filter = lambda f: input_api.FilterSourceFile(
3811 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533812 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3813 for line_num, line in fpath.ChangedContents():
3814 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023815 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533816 results.append(output_api.PresubmitError(
3817 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3818 (fpath.LocalPath(), line_num, deprecated_value, value)))
3819 return results
3820
mohan.reddyf21db962014-10-16 12:26:473821
rlanday6802cf632017-05-30 17:48:363822def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363823 bad_files = {}
3824 for f in input_api.AffectedFiles(include_deletes=False):
3825 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493826 not f.LocalPath().startswith('third_party/blink') and
3827 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363828 continue
3829
Daniel Bratell65b033262019-04-23 08:17:063830 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363831 continue
3832
Vaclav Brozekd5de76a2018-03-17 07:57:503833 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363834 if "#include" in line and "../" in line]
3835 if not relative_includes:
3836 continue
3837 bad_files[f.LocalPath()] = relative_includes
3838
3839 if not bad_files:
3840 return []
3841
3842 error_descriptions = []
3843 for file_path, bad_lines in bad_files.iteritems():
3844 error_description = file_path
3845 for line in bad_lines:
3846 error_description += '\n ' + line
3847 error_descriptions.append(error_description)
3848
3849 results = []
3850 results.append(output_api.PresubmitError(
3851 'You added one or more relative #include paths (including "../").\n'
3852 'These shouldn\'t be used because they can be used to include headers\n'
3853 'from code that\'s not correctly specified as a dependency in the\n'
3854 'relevant BUILD.gn file(s).',
3855 error_descriptions))
3856
3857 return results
3858
Takeshi Yoshinoe387aa32017-08-02 13:16:133859
Daniel Bratell65b033262019-04-23 08:17:063860def _CheckForCcIncludes(input_api, output_api):
3861 """Check that nobody tries to include a cc file. It's a relatively
3862 common error which results in duplicate symbols in object
3863 files. This may not always break the build until someone later gets
3864 very confusing linking errors."""
3865 results = []
3866 for f in input_api.AffectedFiles(include_deletes=False):
3867 # We let third_party code do whatever it wants
3868 if (f.LocalPath().startswith('third_party') and
3869 not f.LocalPath().startswith('third_party/blink') and
3870 not f.LocalPath().startswith('third_party\\blink')):
3871 continue
3872
3873 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3874 continue
3875
3876 for _, line in f.ChangedContents():
3877 if line.startswith('#include "'):
3878 included_file = line.split('"')[1]
3879 if _IsCPlusPlusFile(input_api, included_file):
3880 # The most common naming for external files with C++ code,
3881 # apart from standard headers, is to call them foo.inc, but
3882 # Chromium sometimes uses foo-inc.cc so allow that as well.
3883 if not included_file.endswith(('.h', '-inc.cc')):
3884 results.append(output_api.PresubmitError(
3885 'Only header files or .inc files should be included in other\n'
3886 'C++ files. Compiling the contents of a cc file more than once\n'
3887 'will cause duplicate information in the build which may later\n'
3888 'result in strange link_errors.\n' +
3889 f.LocalPath() + ':\n ' +
3890 line))
3891
3892 return results
3893
3894
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203895def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3896 if not isinstance(key, ast.Str):
3897 return 'Key at line %d must be a string literal' % key.lineno
3898 if not isinstance(value, ast.Dict):
3899 return 'Value at line %d must be a dict' % value.lineno
3900 if len(value.keys) != 1:
3901 return 'Dict at line %d must have single entry' % value.lineno
3902 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3903 return (
3904 'Entry at line %d must have a string literal \'filepath\' as key' %
3905 value.lineno)
3906 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133907
Takeshi Yoshinoe387aa32017-08-02 13:16:133908
Sergey Ulanov4af16052018-11-08 02:41:463909def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203910 if not isinstance(key, ast.Str):
3911 return 'Key at line %d must be a string literal' % key.lineno
3912 if not isinstance(value, ast.List):
3913 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463914 for element in value.elts:
3915 if not isinstance(element, ast.Str):
3916 return 'Watchlist elements on line %d is not a string' % key.lineno
3917 if not email_regex.match(element.s):
3918 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3919 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203920 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133921
Takeshi Yoshinoe387aa32017-08-02 13:16:133922
Sergey Ulanov4af16052018-11-08 02:41:463923def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203924 mismatch_template = (
3925 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3926 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133927
Sergey Ulanov4af16052018-11-08 02:41:463928 email_regex = input_api.re.compile(
3929 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3930
3931 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203932 i = 0
3933 last_key = ''
3934 while True:
3935 if i >= len(wd_dict.keys):
3936 if i >= len(w_dict.keys):
3937 return None
3938 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3939 elif i >= len(w_dict.keys):
3940 return (
3941 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133942
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203943 wd_key = wd_dict.keys[i]
3944 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133945
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203946 result = _CheckWatchlistDefinitionsEntrySyntax(
3947 wd_key, wd_dict.values[i], ast)
3948 if result is not None:
3949 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133950
Sergey Ulanov4af16052018-11-08 02:41:463951 result = _CheckWatchlistsEntrySyntax(
3952 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203953 if result is not None:
3954 return 'Bad entry in WATCHLISTS dict: %s' % result
3955
3956 if wd_key.s != w_key.s:
3957 return mismatch_template % (
3958 '%s at line %d' % (wd_key.s, wd_key.lineno),
3959 '%s at line %d' % (w_key.s, w_key.lineno))
3960
3961 if wd_key.s < last_key:
3962 return (
3963 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3964 (wd_key.lineno, w_key.lineno))
3965 last_key = wd_key.s
3966
3967 i = i + 1
3968
3969
Sergey Ulanov4af16052018-11-08 02:41:463970def _CheckWATCHLISTSSyntax(expression, input_api):
3971 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203972 if not isinstance(expression, ast.Expression):
3973 return 'WATCHLISTS file must contain a valid expression'
3974 dictionary = expression.body
3975 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3976 return 'WATCHLISTS file must have single dict with exactly two entries'
3977
3978 first_key = dictionary.keys[0]
3979 first_value = dictionary.values[0]
3980 second_key = dictionary.keys[1]
3981 second_value = dictionary.values[1]
3982
3983 if (not isinstance(first_key, ast.Str) or
3984 first_key.s != 'WATCHLIST_DEFINITIONS' or
3985 not isinstance(first_value, ast.Dict)):
3986 return (
3987 'The first entry of the dict in WATCHLISTS file must be '
3988 'WATCHLIST_DEFINITIONS dict')
3989
3990 if (not isinstance(second_key, ast.Str) or
3991 second_key.s != 'WATCHLISTS' or
3992 not isinstance(second_value, ast.Dict)):
3993 return (
3994 'The second entry of the dict in WATCHLISTS file must be '
3995 'WATCHLISTS dict')
3996
Sergey Ulanov4af16052018-11-08 02:41:463997 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133998
3999
4000def _CheckWATCHLISTS(input_api, output_api):
4001 for f in input_api.AffectedFiles(include_deletes=False):
4002 if f.LocalPath() == 'WATCHLISTS':
4003 contents = input_api.ReadFile(f, 'r')
4004
4005 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204006 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134007 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204008 # Get an AST tree for it and scan the tree for detailed style checking.
4009 expression = input_api.ast.parse(
4010 contents, filename='WATCHLISTS', mode='eval')
4011 except ValueError as e:
4012 return [output_api.PresubmitError(
4013 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4014 except SyntaxError as e:
4015 return [output_api.PresubmitError(
4016 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4017 except TypeError as e:
4018 return [output_api.PresubmitError(
4019 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134020
Sergey Ulanov4af16052018-11-08 02:41:464021 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204022 if result is not None:
4023 return [output_api.PresubmitError(result)]
4024 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134025
4026 return []
4027
4028
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194029def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4030 """Checks that newly added header files have corresponding GN changes.
4031 Note that this is only a heuristic. To be precise, run script:
4032 build/check_gn_headers.py.
4033 """
4034
4035 def headers(f):
4036 return input_api.FilterSourceFile(
4037 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4038
4039 new_headers = []
4040 for f in input_api.AffectedSourceFiles(headers):
4041 if f.Action() != 'A':
4042 continue
4043 new_headers.append(f.LocalPath())
4044
4045 def gn_files(f):
4046 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4047
4048 all_gn_changed_contents = ''
4049 for f in input_api.AffectedSourceFiles(gn_files):
4050 for _, line in f.ChangedContents():
4051 all_gn_changed_contents += line
4052
4053 problems = []
4054 for header in new_headers:
4055 basename = input_api.os_path.basename(header)
4056 if basename not in all_gn_changed_contents:
4057 problems.append(header)
4058
4059 if problems:
4060 return [output_api.PresubmitPromptWarning(
4061 'Missing GN changes for new header files', items=sorted(problems),
4062 long_text='Please double check whether newly added header files need '
4063 'corresponding changes in gn or gni files.\nThis checking is only a '
4064 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4065 'Read https://crbug.com/661774 for more info.')]
4066 return []
4067
4068
Michael Giuffridad3bc8672018-10-25 22:48:024069def _CheckCorrectProductNameInMessages(input_api, output_api):
4070 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4071
4072 This assumes we won't intentionally reference one product from the other
4073 product.
4074 """
4075 all_problems = []
4076 test_cases = [{
4077 "filename_postfix": "google_chrome_strings.grd",
4078 "correct_name": "Chrome",
4079 "incorrect_name": "Chromium",
4080 }, {
4081 "filename_postfix": "chromium_strings.grd",
4082 "correct_name": "Chromium",
4083 "incorrect_name": "Chrome",
4084 }]
4085
4086 for test_case in test_cases:
4087 problems = []
4088 filename_filter = lambda x: x.LocalPath().endswith(
4089 test_case["filename_postfix"])
4090
4091 # Check each new line. Can yield false positives in multiline comments, but
4092 # easier than trying to parse the XML because messages can have nested
4093 # children, and associating message elements with affected lines is hard.
4094 for f in input_api.AffectedSourceFiles(filename_filter):
4095 for line_num, line in f.ChangedContents():
4096 if "<message" in line or "<!--" in line or "-->" in line:
4097 continue
4098 if test_case["incorrect_name"] in line:
4099 problems.append(
4100 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4101
4102 if problems:
4103 message = (
4104 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4105 % (test_case["correct_name"], test_case["correct_name"],
4106 test_case["incorrect_name"]))
4107 all_problems.append(
4108 output_api.PresubmitPromptWarning(message, items=problems))
4109
4110 return all_problems
4111
4112
Dirk Pranke3c18a382019-03-15 01:07:514113def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4114 # TODO(crbug.com/941824): We need to make sure the entries in
4115 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4116 # so that users of //buildtools in other projects get the same tooling
4117 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4118 # support to gclient, we can eliminate the duplication and delete
4119 # this presubmit check.
4120
4121 # Update this regexp if new revisions are added to the files.
4122 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264123 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514124
4125 # If a user is changing one revision, they need to change the same
4126 # line in both files. This means that any given change should contain
4127 # exactly the same list of changed lines that match the regexps. The
4128 # replace(' ', '') call allows us to ignore whitespace changes to the
4129 # lines. The 'long_text' parameter to the error will contain the
4130 # list of changed lines in both files, which should make it easy enough
4131 # to spot the error without going overboard in this implementation.
4132 revs_changes = {
4133 'DEPS': {},
4134 'buildtools/DEPS': {},
4135 }
4136 long_text = ''
4137
4138 for f in input_api.AffectedFiles(
4139 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4140 for line_num, line in f.ChangedContents():
4141 if rev_regexp.search(line):
4142 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4143 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4144
4145 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4146 return [output_api.PresubmitError(
4147 'Change buildtools revisions in sync in both //DEPS and '
4148 '//buildtools/DEPS.', long_text=long_text + '\n')]
4149 else:
4150 return []
4151
4152
Daniel Bratell93eb6c62019-04-29 20:13:364153def _CheckForTooLargeFiles(input_api, output_api):
4154 """Avoid large files, especially binary files, in the repository since
4155 git doesn't scale well for those. They will be in everyone's repo
4156 clones forever, forever making Chromium slower to clone and work
4157 with."""
4158
4159 # Uploading files to cloud storage is not trivial so we don't want
4160 # to set the limit too low, but the upper limit for "normal" large
4161 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4162 # anything over 20 MB is exceptional.
4163 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4164
4165 too_large_files = []
4166 for f in input_api.AffectedFiles():
4167 # Check both added and modified files (but not deleted files).
4168 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384169 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364170 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4171 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4172
4173 if too_large_files:
4174 message = (
4175 'Do not commit large files to git since git scales badly for those.\n' +
4176 'Instead put the large files in cloud storage and use DEPS to\n' +
4177 'fetch them.\n' + '\n'.join(too_large_files)
4178 )
4179 return [output_api.PresubmitError(
4180 'Too large files found in commit', long_text=message + '\n')]
4181 else:
4182 return []
4183
Max Morozb47503b2019-08-08 21:03:274184
4185def _CheckFuzzTargets(input_api, output_api):
4186 """Checks specific for fuzz target sources."""
4187 EXPORTED_SYMBOLS = [
4188 'LLVMFuzzerInitialize',
4189 'LLVMFuzzerCustomMutator',
4190 'LLVMFuzzerCustomCrossOver',
4191 'LLVMFuzzerMutate',
4192 ]
4193
4194 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4195
4196 def FilterFile(affected_file):
4197 """Ignore libFuzzer source code."""
4198 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4199 black_list = r"^third_party[\\/]libFuzzer"
4200
4201 return input_api.FilterSourceFile(
4202 affected_file,
4203 white_list=[white_list],
4204 black_list=[black_list])
4205
4206 files_with_missing_header = []
4207 for f in input_api.AffectedSourceFiles(FilterFile):
4208 contents = input_api.ReadFile(f, 'r')
4209 if REQUIRED_HEADER in contents:
4210 continue
4211
4212 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4213 files_with_missing_header.append(f.LocalPath())
4214
4215 if not files_with_missing_header:
4216 return []
4217
4218 long_text = (
4219 'If you define any of the libFuzzer optional functions (%s), it is '
4220 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4221 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4222 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4223 'to access command line arguments passed to the fuzzer. Instead, prefer '
4224 'static initialization and shared resources as documented in '
4225 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4226 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4227 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4228 )
4229
4230 return [output_api.PresubmitPromptWarning(
4231 message="Missing '%s' in:" % REQUIRED_HEADER,
4232 items=files_with_missing_header,
4233 long_text=long_text)]
4234
4235
Mohamed Heikald048240a2019-11-12 16:57:374236def _CheckNewImagesWarning(input_api, output_api):
4237 """
4238 Warns authors who add images into the repo to make sure their images are
4239 optimized before committing.
4240 """
4241 images_added = False
4242 image_paths = []
4243 errors = []
4244 filter_lambda = lambda x: input_api.FilterSourceFile(
4245 x,
4246 black_list=(('(?i).*test', r'.*\/junit\/')
4247 + input_api.DEFAULT_BLACK_LIST),
4248 white_list=[r'.*\/(drawable|mipmap)' ]
4249 )
4250 for f in input_api.AffectedFiles(
4251 include_deletes=False, file_filter=filter_lambda):
4252 local_path = f.LocalPath().lower()
4253 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4254 images_added = True
4255 image_paths.append(f)
4256 if images_added:
4257 errors.append(output_api.PresubmitPromptWarning(
4258 'It looks like you are trying to commit some images. If these are '
4259 'non-test-only images, please make sure to read and apply the tips in '
4260 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4261 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4262 'FYI only and will not block your CL on the CQ.', image_paths))
4263 return errors
4264
4265
dgnaa68d5e2015-06-10 10:08:224266def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574267 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224268 results = []
dgnaa68d5e2015-06-10 10:08:224269 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174270 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224271 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294272 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064273 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4274 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424275 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184276 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574277 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374278 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154279 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574280 return results
4281
4282def _AndroidSpecificOnCommitChecks(input_api, output_api):
4283 """Groups commit checks that target android code."""
4284 results = []
4285 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224286 return results
4287
Chris Hall59f8d0c72020-05-01 07:31:194288# TODO(chrishall): could we additionally match on any path owned by
4289# ui/accessibility/OWNERS ?
4290_ACCESSIBILITY_PATHS = (
4291 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4292 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4293 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4294 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4295 r"^content[\\/]browser[\\/]accessibility[\\/]",
4296 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4297 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4298 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4299 r"^ui[\\/]accessibility[\\/]",
4300 r"^ui[\\/]views[\\/]accessibility[\\/]",
4301)
4302
4303def _CheckAccessibilityRelnotesField(input_api, output_api):
4304 """Checks that commits to accessibility code contain an AX-Relnotes field in
4305 their commit message."""
4306 def FileFilter(affected_file):
4307 paths = _ACCESSIBILITY_PATHS
4308 return input_api.FilterSourceFile(affected_file, white_list=paths)
4309
4310 # Only consider changes affecting accessibility paths.
4311 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4312 return []
4313
Akihiro Ota08108e542020-05-20 15:30:534314 # AX-Relnotes can appear in either the description or the footer.
4315 # When searching the description, require 'AX-Relnotes:' to appear at the
4316 # beginning of a line.
4317 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4318 description_has_relnotes = any(ax_regex.match(line)
4319 for line in input_api.change.DescriptionText().lower().splitlines())
4320
4321 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4322 'AX-Relnotes', [])
4323 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194324 return []
4325
4326 # TODO(chrishall): link to Relnotes documentation in message.
4327 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4328 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4329 "user-facing changes"
4330 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4331 "user-facing effects"
4332 "\n if this is confusing or annoying then please contact members "
4333 "of ui/accessibility/OWNERS.")
4334
4335 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224336
[email protected]22c9bd72011-03-27 16:47:394337def _CommonChecks(input_api, output_api):
4338 """Checks common to both upload and commit."""
4339 results = []
4340 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384341 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544342 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084343
4344 author = input_api.change.author_email
4345 if author and author not in _KNOWN_ROBOTS:
4346 results.extend(
4347 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4348
Chris Hall59f8d0c72020-05-01 07:31:194349 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194350 results.extend(
[email protected]760deea2013-12-10 19:33:494351 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234352 results.extend(
4353 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544354 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184355 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344356 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524357 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224358 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444359 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594360 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314361 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064362 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124363 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184364 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224365 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304366 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494367 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034368 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494369 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444370 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294371 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274372 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074373 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544374 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444375 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394376 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554377 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044378 results.extend(
4379 input_api.canned_checks.CheckChangeHasNoTabs(
4380 input_api,
4381 output_api,
4382 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404383 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164384 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084385 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244386 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474387 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044388 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054389 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144390 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234391 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434392 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404393 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154394 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034395 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134396 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264397 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504398 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364399 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064400 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134401 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434402 results.extend(input_api.RunTests(
4403 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264404 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124405 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024406 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514407 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364408 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004409 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514410 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244411
Vaclav Brozekcdc7defb2018-03-20 09:54:354412 for f in input_api.AffectedFiles():
4413 path, name = input_api.os_path.split(f.LocalPath())
4414 if name == 'PRESUBMIT.py':
4415 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004416 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4417 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074418 # The PRESUBMIT.py file (and the directory containing it) might
4419 # have been affected by being moved or removed, so only try to
4420 # run the tests if they still exist.
4421 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4422 input_api, output_api, full_path,
4423 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394424 return results
[email protected]1f7b4172010-01-28 01:17:344425
[email protected]b337cb5b2011-01-23 21:24:054426
[email protected]b8079ae4a2012-12-05 19:56:494427def _CheckPatchFiles(input_api, output_api):
4428 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4429 if f.LocalPath().endswith(('.orig', '.rej'))]
4430 if problems:
4431 return [output_api.PresubmitError(
4432 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034433 else:
4434 return []
[email protected]b8079ae4a2012-12-05 19:56:494435
4436
Kent Tamura5a8755d2017-06-29 23:37:074437def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214438 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4439 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4440 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074441 include_re = input_api.re.compile(
4442 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4443 extension_re = input_api.re.compile(r'\.[a-z]+$')
4444 errors = []
4445 for f in input_api.AffectedFiles():
4446 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4447 continue
4448 found_line_number = None
4449 found_macro = None
4450 for line_num, line in f.ChangedContents():
4451 match = macro_re.search(line)
4452 if match:
4453 found_line_number = line_num
4454 found_macro = match.group(2)
4455 break
4456 if not found_line_number:
4457 continue
4458
4459 found_include = False
4460 for line in f.NewContents():
4461 if include_re.search(line):
4462 found_include = True
4463 break
4464 if found_include:
4465 continue
4466
4467 if not f.LocalPath().endswith('.h'):
4468 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4469 try:
4470 content = input_api.ReadFile(primary_header_path, 'r')
4471 if include_re.search(content):
4472 continue
4473 except IOError:
4474 pass
4475 errors.append('%s:%d %s macro is used without including build/'
4476 'build_config.h.'
4477 % (f.LocalPath(), found_line_number, found_macro))
4478 if errors:
4479 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4480 return []
4481
4482
[email protected]b00342e7f2013-03-26 16:21:544483def _DidYouMeanOSMacro(bad_macro):
4484 try:
4485 return {'A': 'OS_ANDROID',
4486 'B': 'OS_BSD',
4487 'C': 'OS_CHROMEOS',
4488 'F': 'OS_FREEBSD',
4489 'L': 'OS_LINUX',
4490 'M': 'OS_MACOSX',
4491 'N': 'OS_NACL',
4492 'O': 'OS_OPENBSD',
4493 'P': 'OS_POSIX',
4494 'S': 'OS_SOLARIS',
4495 'W': 'OS_WIN'}[bad_macro[3].upper()]
4496 except KeyError:
4497 return ''
4498
4499
4500def _CheckForInvalidOSMacrosInFile(input_api, f):
4501 """Check for sensible looking, totally invalid OS macros."""
4502 preprocessor_statement = input_api.re.compile(r'^\s*#')
4503 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4504 results = []
4505 for lnum, line in f.ChangedContents():
4506 if preprocessor_statement.search(line):
4507 for match in os_macro.finditer(line):
4508 if not match.group(1) in _VALID_OS_MACROS:
4509 good = _DidYouMeanOSMacro(match.group(1))
4510 did_you_mean = ' (did you mean %s?)' % good if good else ''
4511 results.append(' %s:%d %s%s' % (f.LocalPath(),
4512 lnum,
4513 match.group(1),
4514 did_you_mean))
4515 return results
4516
4517
4518def _CheckForInvalidOSMacros(input_api, output_api):
4519 """Check all affected files for invalid OS macros."""
4520 bad_macros = []
tzik3f295992018-12-04 20:32:234521 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474522 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544523 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4524
4525 if not bad_macros:
4526 return []
4527
4528 return [output_api.PresubmitError(
4529 'Possibly invalid OS macro[s] found. Please fix your code\n'
4530 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4531
lliabraa35bab3932014-10-01 12:16:444532
4533def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4534 """Check all affected files for invalid "if defined" macros."""
4535 ALWAYS_DEFINED_MACROS = (
4536 "TARGET_CPU_PPC",
4537 "TARGET_CPU_PPC64",
4538 "TARGET_CPU_68K",
4539 "TARGET_CPU_X86",
4540 "TARGET_CPU_ARM",
4541 "TARGET_CPU_MIPS",
4542 "TARGET_CPU_SPARC",
4543 "TARGET_CPU_ALPHA",
4544 "TARGET_IPHONE_SIMULATOR",
4545 "TARGET_OS_EMBEDDED",
4546 "TARGET_OS_IPHONE",
4547 "TARGET_OS_MAC",
4548 "TARGET_OS_UNIX",
4549 "TARGET_OS_WIN32",
4550 )
4551 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4552 results = []
4553 for lnum, line in f.ChangedContents():
4554 for match in ifdef_macro.finditer(line):
4555 if match.group(1) in ALWAYS_DEFINED_MACROS:
4556 always_defined = ' %s is always defined. ' % match.group(1)
4557 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4558 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4559 lnum,
4560 always_defined,
4561 did_you_mean))
4562 return results
4563
4564
4565def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4566 """Check all affected files for invalid "if defined" macros."""
4567 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054568 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444569 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054570 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214571 continue
lliabraa35bab3932014-10-01 12:16:444572 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4573 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4574
4575 if not bad_macros:
4576 return []
4577
4578 return [output_api.PresubmitError(
4579 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4580 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4581 bad_macros)]
4582
4583
mlamouria82272622014-09-16 18:45:044584def _CheckForIPCRules(input_api, output_api):
4585 """Check for same IPC rules described in
4586 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4587 """
4588 base_pattern = r'IPC_ENUM_TRAITS\('
4589 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4590 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4591
4592 problems = []
4593 for f in input_api.AffectedSourceFiles(None):
4594 local_path = f.LocalPath()
4595 if not local_path.endswith('.h'):
4596 continue
4597 for line_number, line in f.ChangedContents():
4598 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4599 problems.append(
4600 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4601
4602 if problems:
4603 return [output_api.PresubmitPromptWarning(
4604 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4605 else:
4606 return []
4607
[email protected]b00342e7f2013-03-26 16:21:544608
Stephen Martinis97a394142018-06-07 23:06:054609def _CheckForLongPathnames(input_api, output_api):
4610 """Check to make sure no files being submitted have long paths.
4611 This causes issues on Windows.
4612 """
4613 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194614 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054615 local_path = f.LocalPath()
4616 # Windows has a path limit of 260 characters. Limit path length to 200 so
4617 # that we have some extra for the prefix on dev machines and the bots.
4618 if len(local_path) > 200:
4619 problems.append(local_path)
4620
4621 if problems:
4622 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4623 else:
4624 return []
4625
4626
Daniel Bratell8ba52722018-03-02 16:06:144627def _CheckForIncludeGuards(input_api, output_api):
4628 """Check that header files have proper guards against multiple inclusion.
4629 If a file should not have such guards (and it probably should) then it
4630 should include the string "no-include-guard-because-multiply-included".
4631 """
Daniel Bratell6a75baef62018-06-04 10:04:454632 def is_chromium_header_file(f):
4633 # We only check header files under the control of the Chromium
4634 # project. That is, those outside third_party apart from
4635 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324636 # We also exclude *_message_generator.h headers as they use
4637 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454638 file_with_path = input_api.os_path.normpath(f.LocalPath())
4639 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324640 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454641 (not file_with_path.startswith('third_party') or
4642 file_with_path.startswith(
4643 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144644
4645 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344646 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144647
4648 errors = []
4649
Daniel Bratell6a75baef62018-06-04 10:04:454650 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144651 guard_name = None
4652 guard_line_number = None
4653 seen_guard_end = False
4654
4655 file_with_path = input_api.os_path.normpath(f.LocalPath())
4656 base_file_name = input_api.os_path.splitext(
4657 input_api.os_path.basename(file_with_path))[0]
4658 upper_base_file_name = base_file_name.upper()
4659
4660 expected_guard = replace_special_with_underscore(
4661 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144662
4663 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574664 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4665 # are too many (1000+) files with slight deviations from the
4666 # coding style. The most important part is that the include guard
4667 # is there, and that it's unique, not the name so this check is
4668 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144669 #
4670 # As code becomes more uniform, this could be made stricter.
4671
4672 guard_name_pattern_list = [
4673 # Anything with the right suffix (maybe with an extra _).
4674 r'\w+_H__?',
4675
Daniel Bratell39b5b062018-05-16 18:09:574676 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144677 r'\w+_h',
4678
4679 # Anything including the uppercase name of the file.
4680 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4681 upper_base_file_name)) + r'\w*',
4682 ]
4683 guard_name_pattern = '|'.join(guard_name_pattern_list)
4684 guard_pattern = input_api.re.compile(
4685 r'#ifndef\s+(' + guard_name_pattern + ')')
4686
4687 for line_number, line in enumerate(f.NewContents()):
4688 if 'no-include-guard-because-multiply-included' in line:
4689 guard_name = 'DUMMY' # To not trigger check outside the loop.
4690 break
4691
4692 if guard_name is None:
4693 match = guard_pattern.match(line)
4694 if match:
4695 guard_name = match.group(1)
4696 guard_line_number = line_number
4697
Daniel Bratell39b5b062018-05-16 18:09:574698 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454699 # don't match the chromium style guide, but new files should
4700 # get it right.
4701 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574702 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144703 errors.append(output_api.PresubmitPromptWarning(
4704 'Header using the wrong include guard name %s' % guard_name,
4705 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574706 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144707 else:
4708 # The line after #ifndef should have a #define of the same name.
4709 if line_number == guard_line_number + 1:
4710 expected_line = '#define %s' % guard_name
4711 if line != expected_line:
4712 errors.append(output_api.PresubmitPromptWarning(
4713 'Missing "%s" for include guard' % expected_line,
4714 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4715 'Expected: %r\nGot: %r' % (expected_line, line)))
4716
4717 if not seen_guard_end and line == '#endif // %s' % guard_name:
4718 seen_guard_end = True
4719 elif seen_guard_end:
4720 if line.strip() != '':
4721 errors.append(output_api.PresubmitPromptWarning(
4722 'Include guard %s not covering the whole file' % (
4723 guard_name), [f.LocalPath()]))
4724 break # Nothing else to check and enough to warn once.
4725
4726 if guard_name is None:
4727 errors.append(output_api.PresubmitPromptWarning(
4728 'Missing include guard %s' % expected_guard,
4729 [f.LocalPath()],
4730 'Missing include guard in %s\n'
4731 'Recommended name: %s\n'
4732 'This check can be disabled by having the string\n'
4733 'no-include-guard-because-multiply-included in the header.' %
4734 (f.LocalPath(), expected_guard)))
4735
4736 return errors
4737
4738
mostynbb639aca52015-01-07 20:31:234739def _CheckForWindowsLineEndings(input_api, output_api):
4740 """Check source code and known ascii text files for Windows style line
4741 endings.
4742 """
earthdok1b5e0ee2015-03-10 15:19:104743 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234744
4745 file_inclusion_pattern = (
4746 known_text_files,
4747 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4748 )
4749
mostynbb639aca52015-01-07 20:31:234750 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534751 source_file_filter = lambda f: input_api.FilterSourceFile(
4752 f, white_list=file_inclusion_pattern, black_list=None)
4753 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504754 include_file = False
4755 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234756 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504757 include_file = True
4758 if include_file:
4759 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234760
4761 if problems:
4762 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4763 'these files to contain Windows style line endings?\n' +
4764 '\n'.join(problems))]
4765
4766 return []
4767
4768
Vaclav Brozekd5de76a2018-03-17 07:57:504769def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134770 """Checks that all source files use SYSLOG properly."""
4771 syslog_files = []
4772 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564773 for line_number, line in f.ChangedContents():
4774 if 'SYSLOG' in line:
4775 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4776
pastarmovj89f7ee12016-09-20 14:58:134777 if syslog_files:
4778 return [output_api.PresubmitPromptWarning(
4779 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4780 ' calls.\nFiles to check:\n', items=syslog_files)]
4781 return []
4782
4783
[email protected]1f7b4172010-01-28 01:17:344784def CheckChangeOnUpload(input_api, output_api):
4785 results = []
4786 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474787 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284788 results.extend(
jam93a6ee792017-02-08 23:59:224789 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194790 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224791 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134792 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164793 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534794 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194795 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274796 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544797 return results
[email protected]ca8d1982009-02-19 16:33:124798
4799
[email protected]1bfb8322014-04-23 01:02:414800def GetTryServerMasterForBot(bot):
4801 """Returns the Try Server master for the given bot.
4802
[email protected]0bb112362014-07-26 04:38:324803 It tries to guess the master from the bot name, but may still fail
4804 and return None. There is no longer a default master.
4805 """
4806 # Potentially ambiguous bot names are listed explicitly.
4807 master_map = {
tandriie5587792016-07-14 00:34:504808 'chromium_presubmit': 'master.tryserver.chromium.linux',
4809 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414810 }
[email protected]0bb112362014-07-26 04:38:324811 master = master_map.get(bot)
4812 if not master:
wnwen4fbaab82016-05-25 12:54:364813 if 'android' in bot:
tandriie5587792016-07-14 00:34:504814 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364815 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504816 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324817 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504818 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324819 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504820 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324821 return master
[email protected]1bfb8322014-04-23 01:02:414822
4823
[email protected]ca8d1982009-02-19 16:33:124824def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544825 results = []
[email protected]1f7b4172010-01-28 01:17:344826 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574827 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544828 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274829 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344830 input_api,
4831 output_api,
[email protected]2fdd1f362013-01-16 03:56:034832 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274833
jam93a6ee792017-02-08 23:59:224834 results.extend(
4835 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544836 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4837 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384838 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4839 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414840 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4841 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544842 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144843
4844
Rainhard Findlingfc31844c52020-05-15 09:58:264845def _CheckStrings(input_api, output_api):
4846 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024847 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4848 # footer is set to true.
4849 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264850 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024851 footer.lower()
4852 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264853 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024854
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144855 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264856 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144857 import sys
4858 from io import StringIO
4859
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144860 new_or_added_paths = set(f.LocalPath()
4861 for f in input_api.AffectedFiles()
4862 if (f.Action() == 'A' or f.Action() == 'M'))
4863 removed_paths = set(f.LocalPath()
4864 for f in input_api.AffectedFiles(include_deletes=True)
4865 if f.Action() == 'D')
4866
4867 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264868 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164869 if not affected_grds:
4870 return []
4871
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144872 affected_png_paths = [f.AbsoluteLocalPath()
4873 for f in input_api.AffectedFiles()
4874 if (f.LocalPath().endswith('.png'))]
4875
4876 # Check for screenshots. Developers can upload screenshots using
4877 # tools/translation/upload_screenshots.py which finds and uploads
4878 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4879 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4880 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4881 #
4882 # The logic here is as follows:
4883 #
4884 # - If the CL has a .png file under the screenshots directory for a grd
4885 # file, warn the developer. Actual images should never be checked into the
4886 # Chrome repo.
4887 #
4888 # - If the CL contains modified or new messages in grd files and doesn't
4889 # contain the corresponding .sha1 files, warn the developer to add images
4890 # and upload them via tools/translation/upload_screenshots.py.
4891 #
4892 # - If the CL contains modified or new messages in grd files and the
4893 # corresponding .sha1 files, everything looks good.
4894 #
4895 # - If the CL contains removed messages in grd files but the corresponding
4896 # .sha1 files aren't removed, warn the developer to remove them.
4897 unnecessary_screenshots = []
4898 missing_sha1 = []
4899 unnecessary_sha1_files = []
4900
Rainhard Findlingfc31844c52020-05-15 09:58:264901 # This checks verifies that the ICU syntax of messages this CL touched is
4902 # valid, and reports any found syntax errors.
4903 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4904 # without developers being aware of them. Later on, such ICU syntax errors
4905 # break message extraction for translation, hence would block Chromium
4906 # translations until they are fixed.
4907 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144908
4909 def _CheckScreenshotAdded(screenshots_dir, message_id):
4910 sha1_path = input_api.os_path.join(
4911 screenshots_dir, message_id + '.png.sha1')
4912 if sha1_path not in new_or_added_paths:
4913 missing_sha1.append(sha1_path)
4914
4915
4916 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4917 sha1_path = input_api.os_path.join(
4918 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034919 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144920 unnecessary_sha1_files.append(sha1_path)
4921
Rainhard Findlingfc31844c52020-05-15 09:58:264922
4923 def _ValidateIcuSyntax(text, level, signatures):
4924 """Validates ICU syntax of a text string.
4925
4926 Check if text looks similar to ICU and checks for ICU syntax correctness
4927 in this case. Reports various issues with ICU syntax and values of
4928 variants. Supports checking of nested messages. Accumulate information of
4929 each ICU messages found in the text for further checking.
4930
4931 Args:
4932 text: a string to check.
4933 level: a number of current nesting level.
4934 signatures: an accumulator, a list of tuple of (level, variable,
4935 kind, variants).
4936
4937 Returns:
4938 None if a string is not ICU or no issue detected.
4939 A tuple of (message, start index, end index) if an issue detected.
4940 """
4941 valid_types = {
4942 'plural': (frozenset(
4943 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4944 frozenset(['=1', 'other'])),
4945 'selectordinal': (frozenset(
4946 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4947 frozenset(['one', 'other'])),
4948 'select': (frozenset(), frozenset(['other'])),
4949 }
4950
4951 # Check if the message looks like an attempt to use ICU
4952 # plural. If yes - check if its syntax strictly matches ICU format.
4953 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4954 if not like:
4955 signatures.append((level, None, None, None))
4956 return
4957
4958 # Check for valid prefix and suffix
4959 m = re.match(
4960 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4961 r'(plural|selectordinal|select),\s*'
4962 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4963 if not m:
4964 return (('This message looks like an ICU plural, '
4965 'but does not follow ICU syntax.'), like.start(), like.end())
4966 starting, variable, kind, variant_pairs = m.groups()
4967 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4968 if depth:
4969 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4970 len(text))
4971 first = text[0]
4972 ending = text[last_pos:]
4973 if not starting:
4974 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4975 last_pos)
4976 if not ending or '}' not in ending:
4977 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4978 last_pos)
4979 elif first != '{':
4980 return (
4981 ('Invalid ICU format. Extra characters at the start of a complex '
4982 'message (go/icu-message-migration): "%s"') %
4983 starting, 0, len(starting))
4984 elif ending != '}':
4985 return (('Invalid ICU format. Extra characters at the end of a complex '
4986 'message (go/icu-message-migration): "%s"')
4987 % ending, last_pos - 1, len(text) - 1)
4988 if kind not in valid_types:
4989 return (('Unknown ICU message type %s. '
4990 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4991 known, required = valid_types[kind]
4992 defined_variants = set()
4993 for variant, variant_range, value, value_range in variants:
4994 start, end = variant_range
4995 if variant in defined_variants:
4996 return ('Variant "%s" is defined more than once' % variant,
4997 start, end)
4998 elif known and variant not in known:
4999 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5000 start, end)
5001 defined_variants.add(variant)
5002 # Check for nested structure
5003 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5004 if res:
5005 return (res[0], res[1] + value_range[0] + 1,
5006 res[2] + value_range[0] + 1)
5007 missing = required - defined_variants
5008 if missing:
5009 return ('Required variants missing: %s' % ', '.join(missing), 0,
5010 len(text))
5011 signatures.append((level, variable, kind, defined_variants))
5012
5013
5014 def _ParseIcuVariants(text, offset=0):
5015 """Parse variants part of ICU complex message.
5016
5017 Builds a tuple of variant names and values, as well as
5018 their offsets in the input string.
5019
5020 Args:
5021 text: a string to parse
5022 offset: additional offset to add to positions in the text to get correct
5023 position in the complete ICU string.
5024
5025 Returns:
5026 List of tuples, each tuple consist of four fields: variant name,
5027 variant name span (tuple of two integers), variant value, value
5028 span (tuple of two integers).
5029 """
5030 depth, start, end = 0, -1, -1
5031 variants = []
5032 key = None
5033 for idx, char in enumerate(text):
5034 if char == '{':
5035 if not depth:
5036 start = idx
5037 chunk = text[end + 1:start]
5038 key = chunk.strip()
5039 pos = offset + end + 1 + chunk.find(key)
5040 span = (pos, pos + len(key))
5041 depth += 1
5042 elif char == '}':
5043 if not depth:
5044 return variants, depth, offset + idx
5045 depth -= 1
5046 if not depth:
5047 end = idx
5048 variants.append((key, span, text[start:end + 1], (offset + start,
5049 offset + end + 1)))
5050 return variants, depth, offset + end + 1
5051
meacer8c0d3832019-12-26 21:46:165052 try:
5053 old_sys_path = sys.path
5054 sys.path = sys.path + [input_api.os_path.join(
5055 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5056 from helper import grd_helper
5057 finally:
5058 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145059
5060 for f in affected_grds:
5061 file_path = f.LocalPath()
5062 old_id_to_msg_map = {}
5063 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385064 # Note that this code doesn't check if the file has been deleted. This is
5065 # OK because it only uses the old and new file contents and doesn't load
5066 # the file via its path.
5067 # It's also possible that a file's content refers to a renamed or deleted
5068 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5069 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5070 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145071 if file_path.endswith('.grdp'):
5072 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585073 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395074 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585076 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395077 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145078 else:
meacerff8a9b62019-12-10 19:43:585079 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145080 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585081 old_id_to_msg_map = grd_helper.GetGrdMessages(
5082 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145083 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585084 new_id_to_msg_map = grd_helper.GetGrdMessages(
5085 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145086
5087 # Compute added, removed and modified message IDs.
5088 old_ids = set(old_id_to_msg_map)
5089 new_ids = set(new_id_to_msg_map)
5090 added_ids = new_ids - old_ids
5091 removed_ids = old_ids - new_ids
5092 modified_ids = set([])
5093 for key in old_ids.intersection(new_ids):
5094 if (old_id_to_msg_map[key].FormatXml()
5095 != new_id_to_msg_map[key].FormatXml()):
5096 modified_ids.add(key)
5097
5098 grd_name, ext = input_api.os_path.splitext(
5099 input_api.os_path.basename(file_path))
5100 screenshots_dir = input_api.os_path.join(
5101 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5102
Rainhard Findlingfc31844c52020-05-15 09:58:265103 if run_screenshot_check:
5104 # Check the screenshot directory for .png files. Warn if there is any.
5105 for png_path in affected_png_paths:
5106 if png_path.startswith(screenshots_dir):
5107 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145108
Rainhard Findlingfc31844c52020-05-15 09:58:265109 for added_id in added_ids:
5110 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145111
Rainhard Findlingfc31844c52020-05-15 09:58:265112 for modified_id in modified_ids:
5113 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145114
Rainhard Findlingfc31844c52020-05-15 09:58:265115 for removed_id in removed_ids:
5116 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5117
5118 # Check new and changed strings for ICU syntax errors.
5119 for key in added_ids.union(modified_ids):
5120 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5121 err = _ValidateIcuSyntax(msg, 0, [])
5122 if err is not None:
5123 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145124
5125 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265126 if run_screenshot_check:
5127 if unnecessary_screenshots:
5128 results.append(output_api.PresubmitNotifyResult(
5129 'Do not include actual screenshots in the changelist. Run '
5130 'tools/translate/upload_screenshots.py to upload them instead:',
5131 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132
Rainhard Findlingfc31844c52020-05-15 09:58:265133 if missing_sha1:
5134 results.append(output_api.PresubmitNotifyResult(
5135 'You are adding or modifying UI strings.\n'
5136 'To ensure the best translations, take screenshots of the relevant UI '
5137 '(https://g.co/chrome/translation) and add these files to your '
5138 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145139
Rainhard Findlingfc31844c52020-05-15 09:58:265140 if unnecessary_sha1_files:
5141 results.append(output_api.PresubmitNotifyResult(
5142 'You removed strings associated with these files. Remove:',
5143 sorted(unnecessary_sha1_files)))
5144 else:
5145 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5146 'screenshots check.'))
5147
5148 if icu_syntax_errors:
5149 results.append(output_api.PresubmitError(
5150 'ICU syntax errors were found in the following strings (problems or '
5151 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145152
5153 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125154
5155
5156def _CheckTranslationExpectations(input_api, output_api,
5157 repo_root=None,
5158 translation_expectations_path=None,
5159 grd_files=None):
5160 import sys
5161 affected_grds = [f for f in input_api.AffectedFiles()
5162 if (f.LocalPath().endswith('.grd') or
5163 f.LocalPath().endswith('.grdp'))]
5164 if not affected_grds:
5165 return []
5166
5167 try:
5168 old_sys_path = sys.path
5169 sys.path = sys.path + [
5170 input_api.os_path.join(
5171 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5172 from helper import git_helper
5173 from helper import translation_helper
5174 finally:
5175 sys.path = old_sys_path
5176
5177 # Check that translation expectations can be parsed and we can get a list of
5178 # translatable grd files. |repo_root| and |translation_expectations_path| are
5179 # only passed by tests.
5180 if not repo_root:
5181 repo_root = input_api.PresubmitLocalPath()
5182 if not translation_expectations_path:
5183 translation_expectations_path = input_api.os_path.join(
5184 repo_root, 'tools', 'gritsettings',
5185 'translation_expectations.pyl')
5186 if not grd_files:
5187 grd_files = git_helper.list_grds_in_repository(repo_root)
5188
5189 try:
5190 translation_helper.get_translatable_grds(repo_root, grd_files,
5191 translation_expectations_path)
5192 except Exception as e:
5193 return [output_api.PresubmitNotifyResult(
5194 'Failed to get a list of translatable grd files. This happens when:\n'
5195 ' - One of the modified grd or grdp files cannot be parsed or\n'
5196 ' - %s is not updated.\n'
5197 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5198 return []
Ken Rockotc31f4832020-05-29 18:58:515199
5200
5201def _CheckStableMojomChanges(input_api, output_api):
5202 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5203 changed_mojoms = [f for f in input_api.AffectedSourceFiles(None)
5204 if f.LocalPath().endswith('.mojom')]
5205 delta = []
5206 for mojom in changed_mojoms:
5207 old_contents = ''.join(mojom.OldContents()) or None
5208 new_contents = ''.join(mojom.NewContents()) or None
5209 delta.append({
5210 'filename': mojom.LocalPath(),
5211 'old': '\n'.join(mojom.OldContents()) or None,
5212 'new': '\n'.join(mojom.NewContents()) or None,
5213 })
5214
5215 process = input_api.subprocess.Popen(
5216 [input_api.python_executable,
5217 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5218 'public', 'tools', 'mojom',
5219 'check_stable_mojom_compatibility.py'),
5220 '--src-root', input_api.PresubmitLocalPath()],
5221 stdin=input_api.subprocess.PIPE,
5222 stdout=input_api.subprocess.PIPE,
5223 stderr=input_api.subprocess.PIPE,
5224 universal_newlines=True)
5225 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5226 if process.returncode:
5227 return [output_api.PresubmitError(
5228 'One or more [Stable] mojom definitions appears to have been changed '
5229 'in a way that is not backward-compatible.',
5230 long_text=error)]
5231 return []