blob: f78b8eecedcf44047e69c80c9ddf32df324d1386 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1429 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5431 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0432 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4033)
[email protected]ca8d1982009-02-19 16:33:1234
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Fragment of a regular expression that matches C++ and Objective-C++
37# implementation files.
38_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
39
wnwenbdc444e2016-05-25 13:44:1540
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1941# Fragment of a regular expression that matches C++ and Objective-C++
42# header files.
43_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
44
45
[email protected]06e6d0ff2012-12-11 01:36:4446# Regular expression that matches code only used for test binaries
47# (best effort).
48_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0449 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4450 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4451 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1252 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1853 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4454 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0455 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0556 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0457 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4758 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0459 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0860 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0461 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4162 # EarlGrey app side code for tests.
63 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1764 # Views Examples code
65 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4466)
[email protected]ca8d1982009-02-19 16:33:1267
Daniel Bratell609102be2019-03-27 20:53:2168_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1569
[email protected]eea609a2011-11-18 13:10:1270_TEST_ONLY_WARNING = (
71 'You might be calling functions intended only for testing from\n'
72 'production code. It is OK to ignore this warning if you know what\n'
73 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0774 'not perfect. The commit queue will not block on this warning,\n'
75 'however the android-binary-size trybot will block if the method\n'
76 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1277
78
[email protected]cf9b78f2012-11-14 11:40:2879_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4080 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2181 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
82 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2883
Michael Thiessen44457642020-02-06 00:24:1584# Format: Sequence of tuples containing:
85# * Full import path.
86# * Sequence of strings to show when the pattern matches.
87# * Sequence of path or filename exceptions to this rule
88_BANNED_JAVA_IMPORTS = (
89 (
Colin Blundell170d78c82020-03-12 13:56:0490 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1591 (
92 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
93 ),
94 (
95 'net/android/javatests/src/org/chromium/net/'
96 'AndroidProxySelectorTest.java',
97 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:0498 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:1599 ),
100 ),
101)
wnwenbdc444e2016-05-25 13:44:15102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41107_BANNED_JAVA_FUNCTIONS = (
108 (
109 'StrictMode.allowThreadDiskReads()',
110 (
111 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
112 'directly.',
113 ),
114 False,
115 ),
116 (
117 'StrictMode.allowThreadDiskWrites()',
118 (
119 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
120 'directly.',
121 ),
122 False,
123 ),
124)
125
Daniel Bratell609102be2019-03-27 20:53:21126# Format: Sequence of tuples containing:
127# * String pattern or, if starting with a slash, a regular expression.
128# * Sequence of strings to show when the pattern matches.
129# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59130_BANNED_OBJC_FUNCTIONS = (
131 (
132 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59135 'prohibited. Please use CrTrackingArea instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 False,
139 ),
140 (
[email protected]eaae1972014-04-16 04:17:26141 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59144 'instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 False,
148 ),
149 (
150 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertPoint:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertPoint:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
167 (
168 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20169 (
170 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59171 'Please use |convertRect:(point) fromView:nil| instead.',
172 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
173 ),
174 True,
175 ),
176 (
177 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20178 (
179 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59180 'Please use |convertRect:(point) toView:nil| instead.',
181 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
182 ),
183 True,
184 ),
185 (
186 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20187 (
188 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59189 'Please use |convertSize:(point) fromView:nil| instead.',
190 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
191 ),
192 True,
193 ),
194 (
195 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20196 (
197 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59198 'Please use |convertSize:(point) toView:nil| instead.',
199 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
200 ),
201 True,
202 ),
jif65398702016-10-27 10:19:48203 (
204 r"/\s+UTF8String\s*]",
205 (
206 'The use of -[NSString UTF8String] is dangerous as it can return null',
207 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
208 'Please use |SysNSStringToUTF8| instead.',
209 ),
210 True,
211 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34212 (
213 r'__unsafe_unretained',
214 (
215 'The use of __unsafe_unretained is almost certainly wrong, unless',
216 'when interacting with NSFastEnumeration or NSInvocation.',
217 'Please use __weak in files build with ARC, nothing otherwise.',
218 ),
219 False,
220 ),
Avi Drissman7382afa02019-04-29 23:27:13221 (
222 'freeWhenDone:NO',
223 (
224 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
225 'Foundation types is prohibited.',
226 ),
227 True,
228 ),
[email protected]127f18ec2012-06-16 05:05:59229)
230
Daniel Bratell609102be2019-03-27 20:53:21231# Format: Sequence of tuples containing:
232# * String pattern or, if starting with a slash, a regular expression.
233# * Sequence of strings to show when the pattern matches.
234# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54235_BANNED_IOS_OBJC_FUNCTIONS = (
236 (
237 r'/\bTEST[(]',
238 (
239 'TEST() macro should not be used in Objective-C++ code as it does not ',
240 'drain the autorelease pool at the end of the test. Use TEST_F() ',
241 'macro instead with a fixture inheriting from PlatformTest (or a ',
242 'typedef).'
243 ),
244 True,
245 ),
246 (
247 r'/\btesting::Test\b',
248 (
249 'testing::Test should not be used in Objective-C++ code as it does ',
250 'not drain the autorelease pool at the end of the test. Use ',
251 'PlatformTest instead.'
252 ),
253 True,
254 ),
255)
256
Peter K. Lee6c03ccff2019-07-15 14:40:05257# Format: Sequence of tuples containing:
258# * String pattern or, if starting with a slash, a regular expression.
259# * Sequence of strings to show when the pattern matches.
260# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
261_BANNED_IOS_EGTEST_FUNCTIONS = (
262 (
263 r'/\bEXPECT_OCMOCK_VERIFY\b',
264 (
265 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
266 'it is meant for GTests. Use [mock verify] instead.'
267 ),
268 True,
269 ),
270)
271
danakj7a2b7082019-05-21 21:13:51272# Directories that contain deprecated Bind() or Callback types.
273# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36274# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51275# echo "-- $i"
danakj710b4c02019-11-28 16:08:45276# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51277# done
278#
279# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
280# when they have been converted to modern callback types (OnceCallback,
281# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
282# checks for them and prevent regressions.
283_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51284 '^apps/',
danakj7a2b7082019-05-21 21:13:51285 '^base/callback.h', # Intentional.
286 '^chrome/app/',
287 '^chrome/browser/',
288 '^chrome/chrome_elf/',
danakj7a2b7082019-05-21 21:13:51289 '^chrome/common/',
290 '^chrome/installer/',
danakj7a2b7082019-05-21 21:13:51291 '^chrome/renderer/',
292 '^chrome/services/',
293 '^chrome/test/',
294 '^chrome/tools/',
295 '^chrome/utility/',
danakj7a2b7082019-05-21 21:13:51296 '^chromecast/media/',
297 '^chromecast/metrics/',
298 '^chromecast/net/',
299 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51300 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51301 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51302 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51303 '^components/arc/',
304 '^components/assist_ranker/',
305 '^components/autofill/',
306 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51307 '^components/browser_watcher/',
danakj7a2b7082019-05-21 21:13:51308 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51309 '^components/chromeos_camera/',
310 '^components/component_updater/',
311 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51312 '^components/cronet/',
313 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51314 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36315 '^components/dom_distiller/',
Joey Scarr164d7072020-04-21 03:13:39316 '^components/download/internal/common/',
danakj7a2b7082019-05-21 21:13:51317 '^components/drive/',
318 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51319 '^components/feature_engagement/',
320 '^components/feedback/',
321 '^components/flags_ui/',
322 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51323 '^components/guest_view/',
324 '^components/heap_profiling/',
325 '^components/history/',
326 '^components/image_fetcher/',
327 '^components/invalidation/',
328 '^components/keyed_service/',
329 '^components/login/',
330 '^components/metrics/',
331 '^components/metrics_services_manager/',
332 '^components/nacl/',
333 '^components/navigation_interception/',
334 '^components/net_log/',
335 '^components/network_time/',
336 '^components/ntp_snippets/',
337 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51338 '^components/offline_pages/',
339 '^components/omnibox/',
340 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51341 '^components/password_manager/',
342 '^components/payments/',
343 '^components/plugins/',
344 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51345 '^components/proxy_config/',
346 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51347 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51348 '^components/rlz/',
349 '^components/safe_browsing/',
350 '^components/search_engines/',
351 '^components/search_provider_logos/',
352 '^components/security_interstitials/',
353 '^components/security_state/',
354 '^components/services/',
355 '^components/sessions/',
356 '^components/signin/',
357 '^components/ssl_errors/',
358 '^components/storage_monitor/',
359 '^components/subresource_filter/',
360 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51361 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51362 '^components/sync_preferences/',
363 '^components/sync_sessions/',
364 '^components/test/',
365 '^components/tracing/',
366 '^components/translate/',
367 '^components/ukm/',
368 '^components/update_client/',
369 '^components/upload_list/',
370 '^components/variations/',
371 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51372 '^components/webcrypto/',
373 '^components/webdata/',
374 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51375 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20376 '^extensions/browser/',
377 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51378 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51379 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51380 '^ios/chrome/',
381 '^ios/components/',
382 '^ios/net/',
383 '^ios/web/',
384 '^ios/web_view/',
385 '^ipc/',
danakj7a2b7082019-05-21 21:13:51386 '^media/base/',
danakjc8576092019-11-26 19:01:36387 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51388 '^media/cast/',
389 '^media/cdm/',
390 '^media/device_monitors/',
danakj7a2b7082019-05-21 21:13:51391 '^media/filters/',
392 '^media/formats/',
393 '^media/gpu/',
394 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51395 '^media/renderers/',
danakj7a2b7082019-05-21 21:13:51396 '^net/',
397 '^ppapi/proxy/',
398 '^ppapi/shared_impl/',
399 '^ppapi/tests/',
400 '^ppapi/thunk/',
401 '^remoting/base/',
402 '^remoting/client/',
danakj7a2b7082019-05-21 21:13:51403 '^remoting/host/',
404 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51405 '^remoting/protocol/',
danakj7a2b7082019-05-21 21:13:51406 '^services/',
danakj7a2b7082019-05-21 21:13:51407 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51408 '^tools/clang/base_bind_rewriters/', # Intentional.
409 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51410))
[email protected]127f18ec2012-06-16 05:05:59411
Daniel Bratell609102be2019-03-27 20:53:21412# Format: Sequence of tuples containing:
413# * String pattern or, if starting with a slash, a regular expression.
414# * Sequence of strings to show when the pattern matches.
415# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
416# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59417_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20418 (
Dave Tapuska98199b612019-07-10 13:30:44419 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53420 (
421 'New code should not use NULL. Use nullptr instead.',
422 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20423 False,
thomasandersone7caaa9b2017-03-29 19:22:53424 (),
425 ),
Peter Kasting94a56c42019-10-25 21:54:04426 (
427 r'/\busing namespace ',
428 (
429 'Using directives ("using namespace x") are banned by the Google Style',
430 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
431 'Explicitly qualify symbols or use using declarations ("using x::foo").',
432 ),
433 True,
434 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
435 ),
Antonio Gomes07300d02019-03-13 20:59:57436 # Make sure that gtest's FRIEND_TEST() macro is not used; the
437 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
438 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53439 (
[email protected]23e6cbc2012-06-16 18:51:20440 'FRIEND_TEST(',
441 (
[email protected]e3c945502012-06-26 20:01:49442 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20443 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
444 ),
445 False,
[email protected]7345da02012-11-27 14:31:49446 (),
[email protected]23e6cbc2012-06-16 18:51:20447 ),
448 (
Dave Tapuska98199b612019-07-10 13:30:44449 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53450 (
451 'Chrome clients wishing to select events on X windows should use',
452 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
453 'you are selecting events from the GPU process, or if you are using',
454 'an XDisplay other than gfx::GetXDisplay().',
455 ),
456 True,
457 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40458 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04459 r"^ui[\\/]gl[\\/].*\.cc$",
460 r"^media[\\/]gpu[\\/].*\.cc$",
461 r"^gpu[\\/].*\.cc$",
Shahbaz Youssefi1b473182020-06-10 18:05:25462 ),
thomasanderson4b569052016-09-14 20:15:53463 ),
464 (
Dave Tapuska98199b612019-07-10 13:30:44465 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20466 (
thomasanderson11aa41d2017-06-08 22:22:38467 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20468 ),
469 True,
470 (
Egor Paskoce145c42018-09-28 19:31:04471 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
472 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
473 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20474 ),
475 ),
476 (
tomhudsone2c14d552016-05-26 17:07:46477 'setMatrixClip',
478 (
479 'Overriding setMatrixClip() is prohibited; ',
480 'the base function is deprecated. ',
481 ),
482 True,
483 (),
484 ),
485 (
[email protected]52657f62013-05-20 05:30:31486 'SkRefPtr',
487 (
488 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22489 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31490 ),
491 True,
492 (),
493 ),
494 (
495 'SkAutoRef',
496 (
497 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
503 (
504 'SkAutoTUnref',
505 (
506 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22507 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31508 ),
509 True,
510 (),
511 ),
512 (
513 'SkAutoUnref',
514 (
515 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
516 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22517 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31518 ),
519 True,
520 (),
521 ),
[email protected]d89eec82013-12-03 14:10:59522 (
523 r'/HANDLE_EINTR\(.*close',
524 (
525 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
526 'descriptor will be closed, and it is incorrect to retry the close.',
527 'Either call close directly and ignore its return value, or wrap close',
528 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
529 ),
530 True,
531 (),
532 ),
533 (
534 r'/IGNORE_EINTR\((?!.*close)',
535 (
536 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
537 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
538 ),
539 True,
540 (
541 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04542 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
543 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59544 ),
545 ),
[email protected]ec5b3f02014-04-04 18:43:43546 (
547 r'/v8::Extension\(',
548 (
549 'Do not introduce new v8::Extensions into the code base, use',
550 'gin::Wrappable instead. See http://crbug.com/334679',
551 ),
552 True,
[email protected]f55c90ee62014-04-12 00:50:03553 (
Egor Paskoce145c42018-09-28 19:31:04554 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03555 ),
[email protected]ec5b3f02014-04-04 18:43:43556 ),
skyostilf9469f72015-04-20 10:38:52557 (
jame2d1a952016-04-02 00:27:10558 '#pragma comment(lib,',
559 (
560 'Specify libraries to link with in build files and not in the source.',
561 ),
562 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41563 (
tzik3f295992018-12-04 20:32:23564 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04565 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41566 ),
jame2d1a952016-04-02 00:27:10567 ),
fdorayc4ac18d2017-05-01 21:39:59568 (
Gabriel Charette7cc6c432018-04-25 20:52:02569 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59570 (
571 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
572 ),
573 False,
574 (),
575 ),
576 (
Gabriel Charette7cc6c432018-04-25 20:52:02577 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59578 (
579 'Consider using THREAD_CHECKER macros instead of the class directly.',
580 ),
581 False,
582 (),
583 ),
dbeamb6f4fde2017-06-15 04:03:06584 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06585 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
586 (
587 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
588 'deprecated (http://crbug.com/634507). Please avoid converting away',
589 'from the Time types in Chromium code, especially if any math is',
590 'being done on time values. For interfacing with platform/library',
591 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
592 'type converter methods instead. For faking TimeXXX values (for unit',
593 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
594 'other use cases, please contact base/time/OWNERS.',
595 ),
596 False,
597 (),
598 ),
599 (
dbeamb6f4fde2017-06-15 04:03:06600 'CallJavascriptFunctionUnsafe',
601 (
602 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
603 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
604 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
605 ),
606 False,
607 (
Egor Paskoce145c42018-09-28 19:31:04608 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
609 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
610 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06611 ),
612 ),
dskiba1474c2bfd62017-07-20 02:19:24613 (
614 'leveldb::DB::Open',
615 (
616 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
617 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
618 "Chrome's tracing, making their memory usage visible.",
619 ),
620 True,
621 (
622 r'^third_party/leveldatabase/.*\.(cc|h)$',
623 ),
Gabriel Charette0592c3a2017-07-26 12:02:04624 ),
625 (
Chris Mumfordc38afb62017-10-09 17:55:08626 'leveldb::NewMemEnv',
627 (
628 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58629 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
630 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08631 ),
632 True,
633 (
634 r'^third_party/leveldatabase/.*\.(cc|h)$',
635 ),
636 ),
637 (
Gabriel Charetted9839bc2017-07-29 14:17:47638 'RunLoop::QuitCurrent',
639 (
Robert Liao64b7ab22017-08-04 23:03:43640 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
641 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47642 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41643 False,
Gabriel Charetted9839bc2017-07-29 14:17:47644 (),
Gabriel Charettea44975052017-08-21 23:14:04645 ),
646 (
647 'base::ScopedMockTimeMessageLoopTaskRunner',
648 (
Gabriel Charette87cc1af2018-04-25 20:52:51649 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11650 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51651 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
652 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
653 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04654 ),
Gabriel Charette87cc1af2018-04-25 20:52:51655 False,
Gabriel Charettea44975052017-08-21 23:14:04656 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57657 ),
658 (
Dave Tapuska98199b612019-07-10 13:30:44659 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57660 (
661 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02662 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57663 ),
664 True,
665 (),
Francois Doray43670e32017-09-27 12:40:38666 ),
667 (
Peter Kasting991618a62019-06-17 22:00:09668 r'/\bstd::stoi\b',
669 (
670 'std::stoi uses exceptions to communicate results. ',
671 'Use base::StringToInt() instead.',
672 ),
673 True,
674 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
675 ),
676 (
677 r'/\bstd::stol\b',
678 (
679 'std::stol uses exceptions to communicate results. ',
680 'Use base::StringToInt() instead.',
681 ),
682 True,
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
685 (
686 r'/\bstd::stoul\b',
687 (
688 'std::stoul uses exceptions to communicate results. ',
689 'Use base::StringToUint() instead.',
690 ),
691 True,
692 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
693 ),
694 (
695 r'/\bstd::stoll\b',
696 (
697 'std::stoll uses exceptions to communicate results. ',
698 'Use base::StringToInt64() instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
702 ),
703 (
704 r'/\bstd::stoull\b',
705 (
706 'std::stoull uses exceptions to communicate results. ',
707 'Use base::StringToUint64() instead.',
708 ),
709 True,
710 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
711 ),
712 (
713 r'/\bstd::stof\b',
714 (
715 'std::stof uses exceptions to communicate results. ',
716 'For locale-independent values, e.g. reading numbers from disk',
717 'profiles, use base::StringToDouble().',
718 'For user-visible values, parse using ICU.',
719 ),
720 True,
721 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
722 ),
723 (
724 r'/\bstd::stod\b',
725 (
726 'std::stod uses exceptions to communicate results. ',
727 'For locale-independent values, e.g. reading numbers from disk',
728 'profiles, use base::StringToDouble().',
729 'For user-visible values, parse using ICU.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
733 ),
734 (
735 r'/\bstd::stold\b',
736 (
737 'std::stold uses exceptions to communicate results. ',
738 'For locale-independent values, e.g. reading numbers from disk',
739 'profiles, use base::StringToDouble().',
740 'For user-visible values, parse using ICU.',
741 ),
742 True,
743 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
744 ),
745 (
Daniel Bratell69334cc2019-03-26 11:07:45746 r'/\bstd::to_string\b',
747 (
748 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09749 'For locale-independent strings, e.g. writing numbers to disk',
750 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45751 'For user-visible strings, use base::FormatNumber() and',
752 'the related functions in base/i18n/number_formatting.h.',
753 ),
Peter Kasting991618a62019-06-17 22:00:09754 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21755 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45756 ),
757 (
758 r'/\bstd::shared_ptr\b',
759 (
760 'std::shared_ptr should not be used. Use scoped_refptr instead.',
761 ),
762 True,
Andreas Haas63f58792019-11-07 10:56:44763 [_THIRD_PARTY_EXCEPT_BLINK,
764 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
765 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21766 ),
767 (
Peter Kasting991618a62019-06-17 22:00:09768 r'/\bstd::weak_ptr\b',
769 (
770 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
Daniel Bratell609102be2019-03-27 20:53:21776 r'/\blong long\b',
777 (
778 'long long is banned. Use stdint.h if you need a 64 bit number.',
779 ),
780 False, # Only a warning since it is already used.
781 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
782 ),
783 (
784 r'/\bstd::bind\b',
785 (
786 'std::bind is banned because of lifetime risks.',
787 'Use base::BindOnce or base::BindRepeating instead.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\b#include <chrono>\b',
794 (
795 '<chrono> overlaps with Time APIs in base. Keep using',
796 'base classes.',
797 ),
798 True,
799 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
800 ),
801 (
802 r'/\b#include <exception>\b',
803 (
804 'Exceptions are banned and disabled in Chromium.',
805 ),
806 True,
807 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
808 ),
809 (
810 r'/\bstd::function\b',
811 (
812 'std::function is banned. Instead use base::Callback which directly',
813 'supports Chromium\'s weak pointers, ref counting and more.',
814 ),
Peter Kasting991618a62019-06-17 22:00:09815 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21816 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
817 ),
818 (
819 r'/\b#include <random>\b',
820 (
821 'Do not use any random number engines from <random>. Instead',
822 'use base::RandomBitGenerator.',
823 ),
824 True,
825 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
826 ),
827 (
828 r'/\bstd::ratio\b',
829 (
830 'std::ratio is banned by the Google Style Guide.',
831 ),
832 True,
833 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45834 ),
835 (
Francois Doray43670e32017-09-27 12:40:38836 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
837 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
838 (
839 'Use the new API in base/threading/thread_restrictions.h.',
840 ),
Gabriel Charette04b138f2018-08-06 00:03:22841 False,
Francois Doray43670e32017-09-27 12:40:38842 (),
843 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38844 (
danakj7a2b7082019-05-21 21:13:51845 r'/\bbase::Bind\(',
846 (
847 'Please use base::Bind{Once,Repeating} instead',
848 'of base::Bind. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Callback[<:]',
855 (
856 'Please use base::{Once,Repeating}Callback instead',
857 'of base::Callback. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
863 r'/\bbase::Closure\b',
864 (
865 'Please use base::{Once,Repeating}Closure instead',
866 'of base::Closure. (crbug.com/714018)',
867 ),
868 False,
Erik Staaba737d7602019-11-25 18:41:07869 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51870 ),
871 (
Michael Giuffrida7f93d6922019-04-19 14:39:58872 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19873 (
874 'RunMessageLoop is deprecated, use RunLoop instead.',
875 ),
876 False,
877 (),
878 ),
879 (
Dave Tapuska98199b612019-07-10 13:30:44880 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19881 (
882 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
891 "if you're convinced you need this.",
892 ),
893 False,
894 (),
895 ),
896 (
Dave Tapuska98199b612019-07-10 13:30:44897 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19898 (
899 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04900 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19901 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
902 'async events instead of flushing threads.',
903 ),
904 False,
905 (),
906 ),
907 (
908 r'MessageLoopRunner',
909 (
910 'MessageLoopRunner is deprecated, use RunLoop instead.',
911 ),
912 False,
913 (),
914 ),
915 (
Dave Tapuska98199b612019-07-10 13:30:44916 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19917 (
918 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
919 "gab@ if you found a use case where this is the only solution.",
920 ),
921 False,
922 (),
923 ),
924 (
Victor Costane48a2e82019-03-15 22:02:34925 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16926 (
Victor Costane48a2e82019-03-15 22:02:34927 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16928 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
929 ),
930 True,
931 (
932 r'^sql/initialization\.(cc|h)$',
933 r'^third_party/sqlite/.*\.(c|cc|h)$',
934 ),
935 ),
Matt Menke7f520a82018-03-28 21:38:37936 (
Dave Tapuska98199b612019-07-10 13:30:44937 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47938 (
939 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
940 'base::RandomShuffle instead.'
941 ),
942 True,
943 (),
944 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24945 (
946 'ios/web/public/test/http_server',
947 (
948 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
949 ),
950 False,
951 (),
952 ),
Robert Liao764c9492019-01-24 18:46:28953 (
954 'GetAddressOf',
955 (
956 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Robert Liaoe794041e2019-10-03 17:16:46957 'implicated in a few leaks. Use operator& instead. See ',
958 'http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28959 ),
960 True,
961 (),
962 ),
Antonio Gomes07300d02019-03-13 20:59:57963 (
964 'DEFINE_TYPE_CASTS',
965 (
966 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
967 '//third_party/blink/renderer/platform/casting.h.'
968 ),
969 True,
970 (
971 r'^third_party/blink/renderer/.*\.(cc|h)$',
972 ),
973 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38974 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45975 r'/\bIsHTML.+Element\(\b',
976 (
977 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
978 ' helpers IsA<HTMLXXXXElement> from ',
979 '//third_party/blink/renderer/platform/casting.h.'
980 ),
981 False,
982 (
983 r'^third_party/blink/renderer/.*\.(cc|h)$',
984 ),
985 ),
986 (
987 r'/\bToHTML.+Element(|OrNull)\(\b',
988 (
989 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
990 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
991 'and DynamicTo<HTMLXXXXElement> from ',
992 '//third_party/blink/renderer/platform/casting.h.'
993 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
994 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
995 ),
996 False,
997 (
998 r'^third_party/blink/renderer/.*\.(cc|h)$',
999 ),
1000 ),
1001 (
Kinuko Yasuda376c2ce12019-04-16 01:20:371002 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:381003 (
1004 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1005 ),
1006 True,
1007 (),
1008 ),
Ben Lewisa9514602019-04-29 17:53:051009 (
1010 'SHFileOperation',
1011 (
1012 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1013 'complex functions to achieve the same goals. Use IFileOperation for ',
1014 'any esoteric actions instead.'
1015 ),
1016 True,
1017 (),
1018 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181019 (
Cliff Smolinsky81951642019-04-30 21:39:511020 'StringFromGUID2',
1021 (
1022 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1023 'Use base::win::String16FromGUID instead.'
1024 ),
1025 True,
1026 (
1027 r'/base/win/win_util_unittest.cc'
1028 ),
1029 ),
1030 (
1031 'StringFromCLSID',
1032 (
1033 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1034 'Use base::win::String16FromGUID instead.'
1035 ),
1036 True,
1037 (
1038 r'/base/win/win_util_unittest.cc'
1039 ),
1040 ),
1041 (
Avi Drissman7382afa02019-04-29 23:27:131042 'kCFAllocatorNull',
1043 (
1044 'The use of kCFAllocatorNull with the NoCopy creation of ',
1045 'CoreFoundation types is prohibited.',
1046 ),
1047 True,
1048 (),
1049 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291050 (
1051 'mojo::ConvertTo',
1052 (
1053 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1054 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1055 'StringTraits if you would like to convert between custom types and',
1056 'the wire format of mojom types.'
1057 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221058 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291059 (
Wezf89dec092019-09-11 19:38:331060 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1061 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291062 r'^third_party/blink/.*\.(cc|h)$',
1063 r'^content/renderer/.*\.(cc|h)$',
1064 ),
1065 ),
Robert Liao1d78df52019-11-11 20:02:011066 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161067 'GetInterfaceProvider',
1068 (
1069 'InterfaceProvider is deprecated.',
1070 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1071 'or Platform::GetBrowserInterfaceBroker.'
1072 ),
1073 False,
1074 (),
1075 ),
1076 (
Robert Liao1d78df52019-11-11 20:02:011077 'CComPtr',
1078 (
1079 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1080 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1081 'details.'
1082 ),
1083 False,
1084 (),
1085 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201086 (
1087 r'/\b(IFACE|STD)METHOD_?\(',
1088 (
1089 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1090 'Instead, always use IFACEMETHODIMP in the declaration.'
1091 ),
1092 False,
1093 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1094 ),
Allen Bauer53b43fb12020-03-12 17:21:471095 (
1096 'set_owned_by_client',
1097 (
1098 'set_owned_by_client is deprecated.',
1099 'views::View already owns the child views by default. This introduces ',
1100 'a competing ownership model which makes the code difficult to reason ',
1101 'about. See http://crbug.com/1044687 for more details.'
1102 ),
1103 False,
1104 (),
1105 ),
Eric Secklerbe6f48d2020-05-06 18:09:121106 (
1107 r'/\bTRACE_EVENT_ASYNC_',
1108 (
1109 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1110 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1111 ),
1112 False,
1113 (
1114 r'^base/trace_event/.*',
1115 r'^base/tracing/.*',
1116 ),
1117 ),
[email protected]127f18ec2012-06-16 05:05:591118)
1119
Mario Sanchez Prada2472cab2019-09-18 10:58:311120# Format: Sequence of tuples containing:
1121# * String pattern or, if starting with a slash, a regular expression.
1122# * Sequence of strings to show when the pattern matches.
1123_DEPRECATED_MOJO_TYPES = (
1124 (
1125 r'/\bmojo::AssociatedBinding\b',
1126 (
1127 'mojo::AssociatedBinding<Interface> is deprecated.',
1128 'Use mojo::AssociatedReceiver<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::AssociatedBindingSet\b',
1133 (
1134 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1135 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::AssociatedInterfacePtr\b',
1140 (
1141 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1142 'Use mojo::AssociatedRemote<Interface> instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1147 (
1148 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1149 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1150 ),
1151 ),
1152 (
1153 r'/\bmojo::AssociatedInterfaceRequest\b',
1154 (
1155 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1156 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1157 ),
1158 ),
1159 (
1160 r'/\bmojo::Binding\b',
1161 (
1162 'mojo::Binding<Interface> is deprecated.',
1163 'Use mojo::Receiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::BindingSet\b',
1168 (
1169 'mojo::BindingSet<Interface> is deprecated.',
1170 'Use mojo::ReceiverSet<Interface> instead.',
1171 ),
1172 ),
1173 (
1174 r'/\bmojo::InterfacePtr\b',
1175 (
1176 'mojo::InterfacePtr<Interface> is deprecated.',
1177 'Use mojo::Remote<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::InterfacePtrInfo\b',
1182 (
1183 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1184 'Use mojo::PendingRemote<Interface> instead.',
1185 ),
1186 ),
1187 (
1188 r'/\bmojo::InterfaceRequest\b',
1189 (
1190 'mojo::InterfaceRequest<Interface> is deprecated.',
1191 'Use mojo::PendingReceiver<Interface> instead.',
1192 ),
1193 ),
1194 (
1195 r'/\bmojo::MakeRequest\b',
1196 (
1197 'mojo::MakeRequest is deprecated.',
1198 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1203 (
1204 'mojo::MakeRequest is deprecated.',
1205 'Use mojo::AssociatedRemote::'
1206 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongBinding\b',
1211 (
1212 'mojo::MakeStrongBinding is deprecated.',
1213 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1214 'mojo::MakeSelfOwnedReceiver() instead.',
1215 ),
1216 ),
1217 (
1218 r'/\bmojo::MakeStrongAssociatedBinding\b',
1219 (
1220 'mojo::MakeStrongAssociatedBinding is deprecated.',
1221 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1222 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1223 ),
1224 ),
1225 (
1226 r'/\bmojo::StrongAssociatedBindingSet\b',
1227 (
1228 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1229 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1230 ),
1231 ),
1232 (
1233 r'/\bmojo::StrongBindingSet\b',
1234 (
1235 'mojo::StrongBindingSet<Interface> is deprecated.',
1236 'Use mojo::UniqueReceiverSet<Interface> instead.',
1237 ),
1238 ),
1239)
wnwenbdc444e2016-05-25 13:44:151240
mlamouria82272622014-09-16 18:45:041241_IPC_ENUM_TRAITS_DEPRECATED = (
1242 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501243 'See http://www.chromium.org/Home/chromium-security/education/'
1244 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041245
Stephen Martinis97a394142018-06-07 23:06:051246_LONG_PATH_ERROR = (
1247 'Some files included in this CL have file names that are too long (> 200'
1248 ' characters). If committed, these files will cause issues on Windows. See'
1249 ' https://crbug.com/612667 for more details.'
1250)
1251
Shenghua Zhangbfaa38b82017-11-16 21:58:021252_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041253 r".*[\\/]BuildHooksAndroidImpl\.java",
1254 r".*[\\/]LicenseContentProvider\.java",
1255 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281256 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021257]
[email protected]127f18ec2012-06-16 05:05:591258
Mohamed Heikald048240a2019-11-12 16:57:371259# List of image extensions that are used as resources in chromium.
1260_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1261
Sean Kau46e29bc2017-08-28 16:31:161262# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401263_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041264 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401265 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041266 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1267 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041268 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431269 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161270]
1271
1272
[email protected]b00342e7f2013-03-26 16:21:541273_VALID_OS_MACROS = (
1274 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081275 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541276 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121277 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_BSD',
1279 'OS_CAT', # For testing.
1280 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041281 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371283 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541284 'OS_IOS',
1285 'OS_LINUX',
1286 'OS_MACOSX',
1287 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211288 'OS_NACL_NONSFI',
1289 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121290 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_OPENBSD',
1292 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371293 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541295 'OS_WIN',
1296)
1297
1298
Andrew Grieveb773bad2020-06-05 18:00:381299# These are not checked on the public chromium-presubmit trybot.
1300# Add files here that rely on .py files that exists only for target_os="android"
1301# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401302_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391303 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381304 'build/android/devil_chromium.pydeps',
1305 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1306 'build/android/gyp/jinja_template.pydeps',
1307 'build/android/resource_sizes.pydeps',
1308 'build/android/test_runner.pydeps',
1309 'build/android/test_wrapper/logdog_wrapper.pydeps',
1310 'chrome/android/features/create_stripped_java_factory.pydeps',
1311 'testing/scripts/run_android_wpt.pydeps',
1312 'third_party/android_platform/development/scripts/stack.pydeps',
1313]
1314
1315
1316_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'base/android/jni_generator/jni_generator.pydeps',
1318 'base/android/jni_generator/jni_registration_generator.pydeps',
1319 'build/android/gyp/aar.pydeps',
1320 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271321 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381323 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111329 'build/android/gyp/create_app_bundle_apks.pydeps',
1330 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361331 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221332 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361333 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591334 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421336 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361337 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/filter_zip.pydeps',
1339 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361340 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581342 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261344 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011345 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/lint.pydeps',
1347 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361348 'build/android/gyp/merge_manifest.pydeps',
1349 'build/android/gyp/prepare_resources.pydeps',
1350 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461351 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241352 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461354 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561355 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/incremental_install/generate_android_manifest.pydeps',
1357 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361358 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271359 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1360 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381361 'components/module_installer/android/module_desc_java.pydeps',
1362 'net/tools/testserver/testserver.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421363 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1364 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131365 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191366 ('third_party/blink/renderer/bindings/scripts/'
1367 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061368 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221369 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401370]
1371
wnwenbdc444e2016-05-25 13:44:151372
agrievef32bcc72016-04-04 14:57:401373_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1374
1375
Eric Boren6fd2b932018-01-25 15:05:081376# Bypass the AUTHORS check for these accounts.
1377_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591378 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451379 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591380 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521381 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1382 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041383 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271384 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041385 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301386 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081387
1388
Daniel Bratell65b033262019-04-23 08:17:061389def _IsCPlusPlusFile(input_api, file_path):
1390 """Returns True if this file contains C++-like code (and not Python,
1391 Go, Java, MarkDown, ...)"""
1392
1393 ext = input_api.os_path.splitext(file_path)[1]
1394 # This list is compatible with CppChecker.IsCppFile but we should
1395 # consider adding ".c" to it. If we do that we can use this function
1396 # at more places in the code.
1397 return ext in (
1398 '.h',
1399 '.cc',
1400 '.cpp',
1401 '.m',
1402 '.mm',
1403 )
1404
1405def _IsCPlusPlusHeaderFile(input_api, file_path):
1406 return input_api.os_path.splitext(file_path)[1] == ".h"
1407
1408
1409def _IsJavaFile(input_api, file_path):
1410 return input_api.os_path.splitext(file_path)[1] == ".java"
1411
1412
1413def _IsProtoFile(input_api, file_path):
1414 return input_api.os_path.splitext(file_path)[1] == ".proto"
1415
[email protected]55459852011-08-10 15:17:191416def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
1417 """Attempts to prevent use of functions intended only for testing in
1418 non-testing code. For now this is just a best-effort implementation
1419 that ignores header files and may have some false positives. A
1420 better implementation would probably need a proper C++ parser.
1421 """
1422 # We only scan .cc files and the like, as the declaration of
1423 # for-testing functions in header files are hard to distinguish from
1424 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491425 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191426
jochenc0d4808c2015-07-27 09:25:421427 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191428 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091429 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:191430 exclusion_pattern = input_api.re.compile(
1431 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1432 base_function_pattern, base_function_pattern))
1433
1434 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:441435 black_list = (_EXCLUDED_PATHS +
1436 _TEST_CODE_EXCLUDED_PATHS +
1437 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:191438 return input_api.FilterSourceFile(
1439 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491440 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:191441 black_list=black_list)
1442
1443 problems = []
1444 for f in input_api.AffectedSourceFiles(FilterFile):
1445 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:241446 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031447 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461448 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:031449 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:191450 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031451 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:191452
1453 if problems:
[email protected]f7051d52013-04-02 18:31:421454 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031455 else:
1456 return []
[email protected]55459852011-08-10 15:17:191457
1458
Vaclav Brozek7dbc28c2018-03-27 08:35:231459def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
1460 """This is a simplified version of
1461 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1462 """
1463 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1464 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1465 name_pattern = r'ForTest(s|ing)?'
1466 # Describes an occurrence of "ForTest*" inside a // comment.
1467 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1468 # Catch calls.
1469 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1470 # Ignore definitions. (Comments are ignored separately.)
1471 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1472
1473 problems = []
1474 sources = lambda x: input_api.FilterSourceFile(
1475 x,
1476 black_list=(('(?i).*test', r'.*\/junit\/')
1477 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491478 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231479 )
1480 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1481 local_path = f.LocalPath()
1482 is_inside_javadoc = False
1483 for line_number, line in f.ChangedContents():
1484 if is_inside_javadoc and javadoc_end_re.search(line):
1485 is_inside_javadoc = False
1486 if not is_inside_javadoc and javadoc_start_re.search(line):
1487 is_inside_javadoc = True
1488 if is_inside_javadoc:
1489 continue
1490 if (inclusion_re.search(line) and
1491 not comment_re.search(line) and
1492 not exclusion_re.search(line)):
1493 problems.append(
1494 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1495
1496 if problems:
1497 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1498 else:
1499 return []
1500
1501
[email protected]10689ca2011-09-02 02:31:541502def _CheckNoIOStreamInHeaders(input_api, output_api):
1503 """Checks to make sure no .h files include <iostream>."""
1504 files = []
1505 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1506 input_api.re.MULTILINE)
1507 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1508 if not f.LocalPath().endswith('.h'):
1509 continue
1510 contents = input_api.ReadFile(f)
1511 if pattern.search(contents):
1512 files.append(f)
1513
1514 if len(files):
yolandyandaabc6d2016-04-18 18:29:391515 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061516 'Do not #include <iostream> in header files, since it inserts static '
1517 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541518 '#include <ostream>. See http://crbug.com/94794',
1519 files) ]
1520 return []
1521
Danil Chapovalov3518f362018-08-11 16:13:431522def _CheckNoStrCatRedefines(input_api, output_api):
1523 """Checks no windows headers with StrCat redefined are included directly."""
1524 files = []
1525 pattern_deny = input_api.re.compile(
1526 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1527 input_api.re.MULTILINE)
1528 pattern_allow = input_api.re.compile(
1529 r'^#include\s"base/win/windows_defines.inc"',
1530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 contents = input_api.ReadFile(f)
1533 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1534 files.append(f.LocalPath())
1535
1536 if len(files):
1537 return [output_api.PresubmitError(
1538 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1539 'directly since they pollute code with StrCat macro. Instead, '
1540 'include matching header from base/win. See http://crbug.com/856536',
1541 files) ]
1542 return []
1543
[email protected]10689ca2011-09-02 02:31:541544
[email protected]72df4e782012-06-21 16:28:181545def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521546 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181547 problems = []
1548 for f in input_api.AffectedFiles():
1549 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1550 continue
1551
1552 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041553 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181554 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1555
1556 if not problems:
1557 return []
1558 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1559 '\n'.join(problems))]
1560
Dominic Battre033531052018-09-24 15:45:341561def _CheckNoDISABLETypoInTests(input_api, output_api):
1562 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1563
1564 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1565 instead of DISABLED_. To filter false positives, reports are only generated
1566 if a corresponding MAYBE_ line exists.
1567 """
1568 problems = []
1569
1570 # The following two patterns are looked for in tandem - is a test labeled
1571 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1572 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1573 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1574
1575 # This is for the case that a test is disabled on all platforms.
1576 full_disable_pattern = input_api.re.compile(
1577 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1578 input_api.re.MULTILINE)
1579
Katie Df13948e2018-09-25 07:33:441580 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341581 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1582 continue
1583
1584 # Search for MABYE_, DISABLE_ pairs.
1585 disable_lines = {} # Maps of test name to line number.
1586 maybe_lines = {}
1587 for line_num, line in f.ChangedContents():
1588 disable_match = disable_pattern.search(line)
1589 if disable_match:
1590 disable_lines[disable_match.group(1)] = line_num
1591 maybe_match = maybe_pattern.search(line)
1592 if maybe_match:
1593 maybe_lines[maybe_match.group(1)] = line_num
1594
1595 # Search for DISABLE_ occurrences within a TEST() macro.
1596 disable_tests = set(disable_lines.keys())
1597 maybe_tests = set(maybe_lines.keys())
1598 for test in disable_tests.intersection(maybe_tests):
1599 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1600
1601 contents = input_api.ReadFile(f)
1602 full_disable_match = full_disable_pattern.search(contents)
1603 if full_disable_match:
1604 problems.append(' %s' % f.LocalPath())
1605
1606 if not problems:
1607 return []
1608 return [
1609 output_api.PresubmitPromptWarning(
1610 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1611 '\n'.join(problems))
1612 ]
1613
[email protected]72df4e782012-06-21 16:28:181614
danakj61c1aa22015-10-26 19:55:521615def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571616 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521617 errors = []
1618 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1619 input_api.re.MULTILINE)
1620 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1621 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1622 continue
1623 for lnum, line in f.ChangedContents():
1624 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171625 errors.append(output_api.PresubmitError(
1626 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571627 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171628 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521629 return errors
1630
1631
Makoto Shimazu3ad422cd2019-05-08 02:35:141632def _FindHistogramNameInChunk(histogram_name, chunk):
1633 """Tries to find a histogram name or prefix in a line.
1634
1635 Returns the existence of the histogram name, or None if it needs more chunk
1636 to determine."""
mcasasb7440c282015-02-04 14:52:191637 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1638 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141639 if '<affected-histogram' in chunk:
1640 # If the tag is not completed, needs more chunk to get the name.
1641 if not '>' in chunk:
1642 return None
1643 if not 'name="' in chunk:
1644 return False
1645 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1646 # expect the only attribute is the name.
1647 histogram_prefix = chunk.split('"')[1]
1648 return histogram_prefix in histogram_name
1649 # Typically the whole histogram name should in the line.
1650 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191651
1652
1653def _CheckUmaHistogramChanges(input_api, output_api):
1654 """Check that UMA histogram names in touched lines can still be found in other
1655 lines of the patch or in histograms.xml. Note that this check would not catch
1656 the reverse: changes in histograms.xml not matched in the code itself."""
1657 touched_histograms = []
1658 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471659 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1660 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1661 name_pattern = r'"(.*?)"'
1662 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1663 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1664 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1665 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1666 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171667 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191668 for f in input_api.AffectedFiles():
1669 # If histograms.xml itself is modified, keep the modified lines for later.
1670 if f.LocalPath().endswith(('histograms.xml')):
1671 histograms_xml_modifications = f.ChangedContents()
1672 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471673 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1674 single_line_re = single_line_c_re
1675 split_line_prefix_re = split_line_c_prefix_re
1676 elif f.LocalPath().endswith(('java')):
1677 single_line_re = single_line_java_re
1678 split_line_prefix_re = split_line_java_prefix_re
1679 else:
mcasasb7440c282015-02-04 14:52:191680 continue
1681 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171682 if last_line_matched_prefix:
1683 suffix_found = split_line_suffix_re.search(line)
1684 if suffix_found :
1685 touched_histograms.append([suffix_found.group(1), f, line_num])
1686 last_line_matched_prefix = False
1687 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061688 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191689 if found:
1690 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171691 continue
1692 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191693
1694 # Search for the touched histogram names in the local modifications to
1695 # histograms.xml, and, if not found, on the base histograms.xml file.
1696 unmatched_histograms = []
1697 for histogram_info in touched_histograms:
1698 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141699 chunk = ''
mcasasb7440c282015-02-04 14:52:191700 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141701 chunk += line
1702 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1703 if histogram_name_found is None:
1704 continue
1705 chunk = ''
mcasasb7440c282015-02-04 14:52:191706 if histogram_name_found:
1707 break
1708 if not histogram_name_found:
1709 unmatched_histograms.append(histogram_info)
1710
eromanb90c82e7e32015-04-01 15:13:491711 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191712 problems = []
1713 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491714 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191715 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451716 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191717 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141718 chunk = ''
mcasasb7440c282015-02-04 14:52:191719 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141720 chunk += line
1721 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1722 chunk)
1723 if histogram_name_found is None:
1724 continue
1725 chunk = ''
mcasasb7440c282015-02-04 14:52:191726 if histogram_name_found:
1727 break
1728 if not histogram_name_found:
1729 problems.append(' [%s:%d] %s' %
1730 (f.LocalPath(), line_num, histogram_name))
1731
1732 if not problems:
1733 return []
1734 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1735 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491736 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191737
wnwenbdc444e2016-05-25 13:44:151738
yolandyandaabc6d2016-04-18 18:29:391739def _CheckFlakyTestUsage(input_api, output_api):
1740 """Check that FlakyTest annotation is our own instead of the android one"""
1741 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1742 files = []
1743 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1744 if f.LocalPath().endswith('Test.java'):
1745 if pattern.search(input_api.ReadFile(f)):
1746 files.append(f)
1747 if len(files):
1748 return [output_api.PresubmitError(
1749 'Use org.chromium.base.test.util.FlakyTest instead of '
1750 'android.test.FlakyTest',
1751 files)]
1752 return []
mcasasb7440c282015-02-04 14:52:191753
wnwenbdc444e2016-05-25 13:44:151754
[email protected]8ea5d4b2011-09-13 21:49:221755def _CheckNoNewWStrings(input_api, output_api):
1756 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271757 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221758 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201759 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571760 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341761 '/win/' in f.LocalPath() or
1762 'chrome_elf' in f.LocalPath() or
1763 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201764 continue
[email protected]8ea5d4b2011-09-13 21:49:221765
[email protected]a11dbe9b2012-08-07 01:32:581766 allowWString = False
[email protected]b5c24292011-11-28 14:38:201767 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581768 if 'presubmit: allow wstring' in line:
1769 allowWString = True
1770 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271771 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581772 allowWString = False
1773 else:
1774 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221775
[email protected]55463aa62011-10-12 00:48:271776 if not problems:
1777 return []
1778 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581779 ' If you are calling a cross-platform API that accepts a wstring, '
1780 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271781 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221782
1783
[email protected]2a8ac9c2011-10-19 17:20:441784def _CheckNoDEPSGIT(input_api, output_api):
1785 """Make sure .DEPS.git is never modified manually."""
1786 if any(f.LocalPath().endswith('.DEPS.git') for f in
1787 input_api.AffectedFiles()):
1788 return [output_api.PresubmitError(
1789 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1790 'automated system based on what\'s in DEPS and your changes will be\n'
1791 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501792 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1793 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441794 'for more information')]
1795 return []
1796
1797
tandriief664692014-09-23 14:51:471798def _CheckValidHostsInDEPS(input_api, output_api):
1799 """Checks that DEPS file deps are from allowed_hosts."""
1800 # Run only if DEPS file has been modified to annoy fewer bystanders.
1801 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1802 return []
1803 # Outsource work to gclient verify
1804 try:
John Budorickf20c0042019-04-25 23:23:401805 gclient_path = input_api.os_path.join(
1806 input_api.PresubmitLocalPath(),
1807 'third_party', 'depot_tools', 'gclient.py')
1808 input_api.subprocess.check_output(
1809 [input_api.python_executable, gclient_path, 'verify'],
1810 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471811 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201812 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471813 return [output_api.PresubmitError(
1814 'DEPS file must have only git dependencies.',
1815 long_text=error.output)]
1816
1817
Mario Sanchez Prada2472cab2019-09-18 10:58:311818def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1819 type_name, message):
1820 """Helper method for _CheckNoBannedFunctions and _CheckNoDeprecatedMojoTypes.
1821
1822 Returns an string composed of the name of the file, the line number where the
1823 match has been found and the additional text passed as |message| in case the
1824 target type name matches the text inside the line passed as parameter.
1825 """
1826 matched = False
1827 if type_name[0:1] == '/':
1828 regex = type_name[1:]
1829 if input_api.re.search(regex, line):
1830 matched = True
1831 elif type_name in line:
1832 matched = True
1833
1834 result = []
1835 if matched:
1836 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1837 for message_line in message:
1838 result.append(' %s' % message_line)
1839
1840 return result
1841
1842
[email protected]127f18ec2012-06-16 05:05:591843def _CheckNoBannedFunctions(input_api, output_api):
1844 """Make sure that banned functions are not used."""
1845 warnings = []
1846 errors = []
1847
wnwenbdc444e2016-05-25 13:44:151848 def IsBlacklisted(affected_file, blacklist):
1849 local_path = affected_file.LocalPath()
1850 for item in blacklist:
1851 if input_api.re.match(item, local_path):
1852 return True
1853 return False
1854
Peter K. Lee6c03ccff2019-07-15 14:40:051855 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541856 local_path = affected_file.LocalPath()
1857 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1858 return False
1859 basename = input_api.os_path.basename(local_path)
1860 if 'ios' in basename.split('_'):
1861 return True
1862 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1863 if sep and 'ios' in local_path.split(sep):
1864 return True
1865 return False
1866
wnwenbdc444e2016-05-25 13:44:151867 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311868 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1869 func_name, message)
1870 if problems:
wnwenbdc444e2016-05-25 13:44:151871 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311872 errors.extend(problems)
1873 else:
1874 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151875
Eric Stevensona9a980972017-09-23 00:04:411876 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1877 for f in input_api.AffectedFiles(file_filter=file_filter):
1878 for line_num, line in f.ChangedContents():
1879 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1880 CheckForMatch(f, line_num, line, func_name, message, error)
1881
[email protected]127f18ec2012-06-16 05:05:591882 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1883 for f in input_api.AffectedFiles(file_filter=file_filter):
1884 for line_num, line in f.ChangedContents():
1885 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151886 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591887
Peter K. Lee6c03ccff2019-07-15 14:40:051888 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541889 for line_num, line in f.ChangedContents():
1890 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1891 CheckForMatch(f, line_num, line, func_name, message, error)
1892
Peter K. Lee6c03ccff2019-07-15 14:40:051893 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1894 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1895 for line_num, line in f.ChangedContents():
1896 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1897 CheckForMatch(f, line_num, line, func_name, message, error)
1898
[email protected]127f18ec2012-06-16 05:05:591899 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1900 for f in input_api.AffectedFiles(file_filter=file_filter):
1901 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491902 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491903 if IsBlacklisted(f, excluded_paths):
1904 continue
wnwenbdc444e2016-05-25 13:44:151905 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591906
1907 result = []
1908 if (warnings):
1909 result.append(output_api.PresubmitPromptWarning(
1910 'Banned functions were used.\n' + '\n'.join(warnings)))
1911 if (errors):
1912 result.append(output_api.PresubmitError(
1913 'Banned functions were used.\n' + '\n'.join(errors)))
1914 return result
1915
1916
Michael Thiessen44457642020-02-06 00:24:151917def _CheckAndroidNoBannedImports(input_api, output_api):
1918 """Make sure that banned java imports are not used."""
1919 errors = []
1920
1921 def IsException(path, exceptions):
1922 for exception in exceptions:
1923 if (path.startswith(exception)):
1924 return True
1925 return False
1926
1927 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1928 for f in input_api.AffectedFiles(file_filter=file_filter):
1929 for line_num, line in f.ChangedContents():
1930 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1931 if IsException(f.LocalPath(), exceptions):
1932 continue;
1933 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1934 'import ' + import_name, message)
1935 if problems:
1936 errors.extend(problems)
1937 result = []
1938 if (errors):
1939 result.append(output_api.PresubmitError(
1940 'Banned imports were used.\n' + '\n'.join(errors)))
1941 return result
1942
1943
Mario Sanchez Prada2472cab2019-09-18 10:58:311944def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1945 """Make sure that old Mojo types are not used."""
1946 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571947 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311948
Mario Sanchez Pradaaab91382019-12-19 08:57:091949 # For any path that is not an "ok" or an "error" path, a warning will be
1950 # raised if deprecated mojo types are found.
1951 ok_paths = ['components/arc']
1952 error_paths = ['third_party/blink', 'content']
1953
Mario Sanchez Prada2472cab2019-09-18 10:58:311954 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1955 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571956 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091957 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311958 continue
1959
1960 for line_num, line in f.ChangedContents():
1961 for func_name, message in _DEPRECATED_MOJO_TYPES:
1962 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1963 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571964
Mario Sanchez Prada2472cab2019-09-18 10:58:311965 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091966 # Raise errors inside |error_paths| and warnings everywhere else.
1967 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571968 errors.extend(problems)
1969 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311970 warnings.extend(problems)
1971
1972 result = []
1973 if (warnings):
1974 result.append(output_api.PresubmitPromptWarning(
1975 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571976 if (errors):
1977 result.append(output_api.PresubmitError(
1978 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311979 return result
1980
1981
[email protected]6c063c62012-07-11 19:11:061982def _CheckNoPragmaOnce(input_api, output_api):
1983 """Make sure that banned functions are not used."""
1984 files = []
1985 pattern = input_api.re.compile(r'^#pragma\s+once',
1986 input_api.re.MULTILINE)
1987 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1988 if not f.LocalPath().endswith('.h'):
1989 continue
1990 contents = input_api.ReadFile(f)
1991 if pattern.search(contents):
1992 files.append(f)
1993
1994 if files:
1995 return [output_api.PresubmitError(
1996 'Do not use #pragma once in header files.\n'
1997 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1998 files)]
1999 return []
2000
[email protected]127f18ec2012-06-16 05:05:592001
[email protected]e7479052012-09-19 00:26:122002def _CheckNoTrinaryTrueFalse(input_api, output_api):
2003 """Checks to make sure we don't introduce use of foo ? true : false."""
2004 problems = []
2005 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2006 for f in input_api.AffectedFiles():
2007 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2008 continue
2009
2010 for line_num, line in f.ChangedContents():
2011 if pattern.match(line):
2012 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2013
2014 if not problems:
2015 return []
2016 return [output_api.PresubmitPromptWarning(
2017 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2018 '\n'.join(problems))]
2019
2020
[email protected]55f9f382012-07-31 11:02:182021def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282022 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182023 change. Breaking - rules is an error, breaking ! rules is a
2024 warning.
2025 """
mohan.reddyf21db962014-10-16 12:26:472026 import sys
[email protected]55f9f382012-07-31 11:02:182027 # We need to wait until we have an input_api object and use this
2028 # roundabout construct to import checkdeps because this file is
2029 # eval-ed and thus doesn't have __file__.
2030 original_sys_path = sys.path
2031 try:
2032 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472033 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182034 import checkdeps
[email protected]55f9f382012-07-31 11:02:182035 from rules import Rule
2036 finally:
2037 # Restore sys.path to what it was before.
2038 sys.path = original_sys_path
2039
2040 added_includes = []
rhalavati08acd232017-04-03 07:23:282041 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242042 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182043 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062044 if _IsCPlusPlusFile(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_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062047 elif _IsProtoFile(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_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062050 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502051 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082052 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182053
[email protected]26385172013-05-09 23:11:352054 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182055
2056 error_descriptions = []
2057 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282058 error_subjects = set()
2059 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182060 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2061 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082062 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182063 description_with_path = '%s\n %s' % (path, rule_description)
2064 if rule_type == Rule.DISALLOW:
2065 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282066 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182067 else:
2068 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282069 warning_subjects.add("#includes")
2070
2071 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2072 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082073 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282074 description_with_path = '%s\n %s' % (path, rule_description)
2075 if rule_type == Rule.DISALLOW:
2076 error_descriptions.append(description_with_path)
2077 error_subjects.add("imports")
2078 else:
2079 warning_descriptions.append(description_with_path)
2080 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182081
Jinsuk Kim5a092672017-10-24 22:42:242082 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022083 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082084 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242085 description_with_path = '%s\n %s' % (path, rule_description)
2086 if rule_type == Rule.DISALLOW:
2087 error_descriptions.append(description_with_path)
2088 error_subjects.add("imports")
2089 else:
2090 warning_descriptions.append(description_with_path)
2091 warning_subjects.add("imports")
2092
[email protected]55f9f382012-07-31 11:02:182093 results = []
2094 if error_descriptions:
2095 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282096 'You added one or more %s that violate checkdeps rules.'
2097 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182098 error_descriptions))
2099 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422100 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282101 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182102 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282103 '%s? See relevant DEPS file(s) for details and contacts.' %
2104 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182105 warning_descriptions))
2106 return results
2107
2108
[email protected]fbcafe5a2012-08-08 15:31:222109def _CheckFilePermissions(input_api, output_api):
2110 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152111 if input_api.platform == 'win32':
2112 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292113 checkperms_tool = input_api.os_path.join(
2114 input_api.PresubmitLocalPath(),
2115 'tools', 'checkperms', 'checkperms.py')
2116 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472117 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392118 with input_api.CreateTemporaryFile() as file_list:
2119 for f in input_api.AffectedFiles():
2120 # checkperms.py file/directory arguments must be relative to the
2121 # repository.
2122 file_list.write(f.LocalPath() + '\n')
2123 file_list.close()
2124 args += ['--file-list', file_list.name]
2125 try:
2126 input_api.subprocess.check_output(args)
2127 return []
2128 except input_api.subprocess.CalledProcessError as error:
2129 return [output_api.PresubmitError(
2130 'checkperms.py failed:',
2131 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222132
2133
robertocn832f5992017-01-04 19:01:302134def _CheckTeamTags(input_api, output_api):
2135 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2136 checkteamtags_tool = input_api.os_path.join(
2137 input_api.PresubmitLocalPath(),
2138 'tools', 'checkteamtags', 'checkteamtags.py')
2139 args = [input_api.python_executable, checkteamtags_tool,
2140 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222141 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302142 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2143 'OWNERS']
2144 try:
2145 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052146 warnings = input_api.subprocess.check_output(args + files).splitlines()
2147 if warnings:
2148 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302149 return []
2150 except input_api.subprocess.CalledProcessError as error:
2151 return [output_api.PresubmitError(
2152 'checkteamtags.py failed:',
2153 long_text=error.output)]
2154
2155
[email protected]c8278b32012-10-30 20:35:492156def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2157 """Makes sure we don't include ui/aura/window_property.h
2158 in header files.
2159 """
2160 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2161 errors = []
2162 for f in input_api.AffectedFiles():
2163 if not f.LocalPath().endswith('.h'):
2164 continue
2165 for line_num, line in f.ChangedContents():
2166 if pattern.match(line):
2167 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2168
2169 results = []
2170 if errors:
2171 results.append(output_api.PresubmitError(
2172 'Header files should not include ui/aura/window_property.h', errors))
2173 return results
2174
2175
[email protected]70ca77752012-11-20 03:45:032176def _CheckForVersionControlConflictsInFile(input_api, f):
2177 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2178 errors = []
2179 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162180 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232181 # First-level headers in markdown look a lot like version control
2182 # conflict markers. http://daringfireball.net/projects/markdown/basics
2183 continue
[email protected]70ca77752012-11-20 03:45:032184 if pattern.match(line):
2185 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2186 return errors
2187
2188
2189def _CheckForVersionControlConflicts(input_api, output_api):
2190 """Usually this is not intentional and will cause a compile failure."""
2191 errors = []
2192 for f in input_api.AffectedFiles():
2193 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2194
2195 results = []
2196 if errors:
2197 results.append(output_api.PresubmitError(
2198 'Version control conflict markers found, please resolve.', errors))
2199 return results
2200
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202201
estadee17314a02017-01-12 16:22:162202def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2203 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2204 errors = []
2205 for f in input_api.AffectedFiles():
2206 for line_num, line in f.ChangedContents():
2207 if pattern.search(line):
2208 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2209
2210 results = []
2211 if errors:
2212 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502213 'Found Google support URL addressed by answer number. Please replace '
2214 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162215 return results
2216
[email protected]70ca77752012-11-20 03:45:032217
[email protected]06e6d0ff2012-12-11 01:36:442218def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2219 def FilterFile(affected_file):
2220 """Filter function for use with input_api.AffectedSourceFiles,
2221 below. This filters out everything except non-test files from
2222 top-level directories that generally speaking should not hard-code
2223 service URLs (e.g. src/android_webview/, src/content/ and others).
2224 """
2225 return input_api.FilterSourceFile(
2226 affected_file,
Egor Paskoce145c42018-09-28 19:31:042227 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442228 black_list=(_EXCLUDED_PATHS +
2229 _TEST_CODE_EXCLUDED_PATHS +
2230 input_api.DEFAULT_BLACK_LIST))
2231
reillyi38965732015-11-16 18:27:332232 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2233 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462234 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2235 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442236 problems = [] # items are (filename, line_number, line)
2237 for f in input_api.AffectedSourceFiles(FilterFile):
2238 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462239 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442240 problems.append((f.LocalPath(), line_num, line))
2241
2242 if problems:
[email protected]f7051d52013-04-02 18:31:422243 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442244 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582245 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442246 [' %s:%d: %s' % (
2247 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032248 else:
2249 return []
[email protected]06e6d0ff2012-12-11 01:36:442250
2251
James Cook6b6597c2019-11-06 22:05:292252def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2253 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2254 def FileFilter(affected_file):
2255 """Includes directories known to be Chrome OS only."""
2256 return input_api.FilterSourceFile(
2257 affected_file,
2258 white_list=('^ash/',
2259 '^chromeos/', # Top-level src/chromeos.
2260 '/chromeos/', # Any path component.
2261 '^components/arc',
2262 '^components/exo'),
2263 black_list=(input_api.DEFAULT_BLACK_LIST))
2264
2265 prefs = []
2266 priority_prefs = []
2267 for f in input_api.AffectedFiles(file_filter=FileFilter):
2268 for line_num, line in f.ChangedContents():
2269 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2270 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2271 prefs.append(' %s' % line)
2272 if input_api.re.search(
2273 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2274 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2275 priority_prefs.append(' %s' % line)
2276
2277 results = []
2278 if (prefs):
2279 results.append(output_api.PresubmitPromptWarning(
2280 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2281 'by browser sync settings. If these prefs should be controlled by OS '
2282 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2283 if (priority_prefs):
2284 results.append(output_api.PresubmitPromptWarning(
2285 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2286 'controlled by browser sync settings. If these prefs should be '
2287 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2288 'instead.\n' + '\n'.join(prefs)))
2289 return results
2290
2291
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492292# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272293def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2294 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312295 The native_client_sdk directory is excluded because it has auto-generated PNG
2296 files for documentation.
[email protected]d2530012013-01-25 16:39:272297 """
[email protected]d2530012013-01-25 16:39:272298 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492299 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042300 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312301 file_filter = lambda f: input_api.FilterSourceFile(
2302 f, white_list=white_list, black_list=black_list)
2303 for f in input_api.AffectedFiles(include_deletes=False,
2304 file_filter=file_filter):
2305 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272306
2307 results = []
2308 if errors:
2309 results.append(output_api.PresubmitError(
2310 'The name of PNG files should not have abbreviations. \n'
2311 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2312 'Contact [email protected] if you have questions.', errors))
2313 return results
2314
2315
Daniel Cheng4dcdb6b2017-04-13 08:30:172316def _ExtractAddRulesFromParsedDeps(parsed_deps):
2317 """Extract the rules that add dependencies from a parsed DEPS file.
2318
2319 Args:
2320 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2321 add_rules = set()
2322 add_rules.update([
2323 rule[1:] for rule in parsed_deps.get('include_rules', [])
2324 if rule.startswith('+') or rule.startswith('!')
2325 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502326 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172327 {}).iteritems():
2328 add_rules.update([
2329 rule[1:] for rule in rules
2330 if rule.startswith('+') or rule.startswith('!')
2331 ])
2332 return add_rules
2333
2334
2335def _ParseDeps(contents):
2336 """Simple helper for parsing DEPS files."""
2337 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172338 class _VarImpl:
2339
2340 def __init__(self, local_scope):
2341 self._local_scope = local_scope
2342
2343 def Lookup(self, var_name):
2344 """Implements the Var syntax."""
2345 try:
2346 return self._local_scope['vars'][var_name]
2347 except KeyError:
2348 raise Exception('Var is not defined: %s' % var_name)
2349
2350 local_scope = {}
2351 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172352 'Var': _VarImpl(local_scope).Lookup,
2353 }
2354 exec contents in global_scope, local_scope
2355 return local_scope
2356
2357
2358def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082359 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412360 a set of DEPS entries that we should look up.
2361
2362 For a directory (rather than a specific filename) we fake a path to
2363 a specific filename by adding /DEPS. This is chosen as a file that
2364 will seldom or never be subject to per-file include_rules.
2365 """
[email protected]2b438d62013-11-14 17:54:142366 # We ignore deps entries on auto-generated directories.
2367 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082368
Daniel Cheng4dcdb6b2017-04-13 08:30:172369 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2370 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2371
2372 added_deps = new_deps.difference(old_deps)
2373
[email protected]2b438d62013-11-14 17:54:142374 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172375 for added_dep in added_deps:
2376 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2377 continue
2378 # Assume that a rule that ends in .h is a rule for a specific file.
2379 if added_dep.endswith('.h'):
2380 results.add(added_dep)
2381 else:
2382 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082383 return results
2384
2385
[email protected]e871964c2013-05-13 14:14:552386def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2387 """When a dependency prefixed with + is added to a DEPS file, we
2388 want to make sure that the change is reviewed by an OWNER of the
2389 target file or directory, to avoid layering violations from being
2390 introduced. This check verifies that this happens.
2391 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172392 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242393
2394 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492395 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242396 for f in input_api.AffectedFiles(include_deletes=False,
2397 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552398 filename = input_api.os_path.basename(f.LocalPath())
2399 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172400 virtual_depended_on_files.update(_CalculateAddedDeps(
2401 input_api.os_path,
2402 '\n'.join(f.OldContents()),
2403 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552404
[email protected]e871964c2013-05-13 14:14:552405 if not virtual_depended_on_files:
2406 return []
2407
2408 if input_api.is_committing:
2409 if input_api.tbr:
2410 return [output_api.PresubmitNotifyResult(
2411 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272412 if input_api.dry_run:
2413 return [output_api.PresubmitNotifyResult(
2414 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552415 if not input_api.change.issue:
2416 return [output_api.PresubmitError(
2417 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402418 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552419 output = output_api.PresubmitError
2420 else:
2421 output = output_api.PresubmitNotifyResult
2422
2423 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502424 owner_email, reviewers = (
2425 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2426 input_api,
2427 owners_db.email_regexp,
2428 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552429
2430 owner_email = owner_email or input_api.change.author_email
2431
[email protected]de4f7d22013-05-23 14:27:462432 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512433 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462434 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552435 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2436 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412437
2438 # We strip the /DEPS part that was added by
2439 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2440 # directory.
2441 def StripDeps(path):
2442 start_deps = path.rfind('/DEPS')
2443 if start_deps != -1:
2444 return path[:start_deps]
2445 else:
2446 return path
2447 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552448 for path in missing_files]
2449
2450 if unapproved_dependencies:
2451 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152452 output('You need LGTM from owners of depends-on paths in DEPS that were '
2453 'modified in this CL:\n %s' %
2454 '\n '.join(sorted(unapproved_dependencies)))]
2455 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2456 output_list.append(output(
2457 'Suggested missing target path OWNERS:\n %s' %
2458 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552459 return output_list
2460
2461 return []
2462
2463
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492464# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402465def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492466 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402467 black_list = (_EXCLUDED_PATHS +
2468 _TEST_CODE_EXCLUDED_PATHS +
2469 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042470 (r"^base[\\/]logging\.h$",
2471 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222472 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042473 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2474 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2475 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122476 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182477 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152478 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032479 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152480 r"^chrome[\\/]chrome_cleaner[\\/].*",
2481 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2482 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042483 r"^chromecast[\\/]",
2484 r"^cloud_print[\\/]",
2485 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482486 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052487 r"^components[\\/]media_control[\\/]renderer[\\/]"
2488 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042489 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462490 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042491 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462492 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042493 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252494 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042495 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2496 r"^courgette[\\/]courgette_tool\.cc$",
2497 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272498 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002499 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332500 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042501 r"^ipc[\\/]ipc_logging\.cc$",
2502 r"^native_client_sdk[\\/]",
2503 r"^remoting[\\/]base[\\/]logging\.h$",
2504 r"^remoting[\\/]host[\\/].*",
2505 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062506 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332507 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042508 r"^tools[\\/]",
2509 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2510 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Shahbaz Youssefi1b473182020-06-10 18:05:252511 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:402512 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492513 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402514
thomasanderson625d3932017-03-29 07:16:582515 log_info = set([])
2516 printf = set([])
[email protected]85218562013-11-22 07:41:402517
2518 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582519 for _, line in f.ChangedContents():
2520 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2521 log_info.add(f.LocalPath())
2522 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2523 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372524
thomasanderson625d3932017-03-29 07:16:582525 if input_api.re.search(r"\bprintf\(", line):
2526 printf.add(f.LocalPath())
2527 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2528 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402529
2530 if log_info:
2531 return [output_api.PresubmitError(
2532 'These files spam the console log with LOG(INFO):',
2533 items=log_info)]
2534 if printf:
2535 return [output_api.PresubmitError(
2536 'These files spam the console log with printf/fprintf:',
2537 items=printf)]
2538 return []
2539
2540
[email protected]49aa76a2013-12-04 06:59:162541def _CheckForAnonymousVariables(input_api, output_api):
2542 """These types are all expected to hold locks while in scope and
2543 so should never be anonymous (which causes them to be immediately
2544 destroyed)."""
2545 they_who_must_be_named = [
2546 'base::AutoLock',
2547 'base::AutoReset',
2548 'base::AutoUnlock',
2549 'SkAutoAlphaRestore',
2550 'SkAutoBitmapShaderInstall',
2551 'SkAutoBlitterChoose',
2552 'SkAutoBounderCommit',
2553 'SkAutoCallProc',
2554 'SkAutoCanvasRestore',
2555 'SkAutoCommentBlock',
2556 'SkAutoDescriptor',
2557 'SkAutoDisableDirectionCheck',
2558 'SkAutoDisableOvalCheck',
2559 'SkAutoFree',
2560 'SkAutoGlyphCache',
2561 'SkAutoHDC',
2562 'SkAutoLockColors',
2563 'SkAutoLockPixels',
2564 'SkAutoMalloc',
2565 'SkAutoMaskFreeImage',
2566 'SkAutoMutexAcquire',
2567 'SkAutoPathBoundsUpdate',
2568 'SkAutoPDFRelease',
2569 'SkAutoRasterClipValidate',
2570 'SkAutoRef',
2571 'SkAutoTime',
2572 'SkAutoTrace',
2573 'SkAutoUnref',
2574 ]
2575 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2576 # bad: base::AutoLock(lock.get());
2577 # not bad: base::AutoLock lock(lock.get());
2578 bad_pattern = input_api.re.compile(anonymous)
2579 # good: new base::AutoLock(lock.get())
2580 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2581 errors = []
2582
2583 for f in input_api.AffectedFiles():
2584 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2585 continue
2586 for linenum, line in f.ChangedContents():
2587 if bad_pattern.search(line) and not good_pattern.search(line):
2588 errors.append('%s:%d' % (f.LocalPath(), linenum))
2589
2590 if errors:
2591 return [output_api.PresubmitError(
2592 'These lines create anonymous variables that need to be named:',
2593 items=errors)]
2594 return []
2595
2596
Peter Kasting4844e46e2018-02-23 07:27:102597def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532598 # Returns whether |template_str| is of the form <T, U...> for some types T
2599 # and U. Assumes that |template_str| is already in the form <...>.
2600 def HasMoreThanOneArg(template_str):
2601 # Level of <...> nesting.
2602 nesting = 0
2603 for c in template_str:
2604 if c == '<':
2605 nesting += 1
2606 elif c == '>':
2607 nesting -= 1
2608 elif c == ',' and nesting == 1:
2609 return True
2610 return False
2611
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492612 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102613 sources = lambda affected_file: input_api.FilterSourceFile(
2614 affected_file,
2615 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2616 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492617 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552618
2619 # Pattern to capture a single "<...>" block of template arguments. It can
2620 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2621 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2622 # latter would likely require counting that < and > match, which is not
2623 # expressible in regular languages. Should the need arise, one can introduce
2624 # limited counting (matching up to a total number of nesting depth), which
2625 # should cover all practical cases for already a low nesting limit.
2626 template_arg_pattern = (
2627 r'<[^>]*' # Opening block of <.
2628 r'>([^<]*>)?') # Closing block of >.
2629 # Prefix expressing that whatever follows is not already inside a <...>
2630 # block.
2631 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102632 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552633 not_inside_template_arg_pattern
2634 + r'\bstd::unique_ptr'
2635 + template_arg_pattern
2636 + r'\(\)')
2637
2638 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2639 template_arg_no_array_pattern = (
2640 r'<[^>]*[^]]' # Opening block of <.
2641 r'>([^(<]*[^]]>)?') # Closing block of >.
2642 # Prefix saying that what follows is the start of an expression.
2643 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2644 # Suffix saying that what follows are call parentheses with a non-empty list
2645 # of arguments.
2646 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532647 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552648 return_construct_pattern = input_api.re.compile(
2649 start_of_expr_pattern
2650 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532651 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552652 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532653 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552654 + nonempty_arg_list_pattern)
2655
Vaclav Brozek851d9602018-04-04 16:13:052656 problems_constructor = []
2657 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102658 for f in input_api.AffectedSourceFiles(sources):
2659 for line_number, line in f.ChangedContents():
2660 # Disallow:
2661 # return std::unique_ptr<T>(foo);
2662 # bar = std::unique_ptr<T>(foo);
2663 # But allow:
2664 # return std::unique_ptr<T[]>(foo);
2665 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532666 # And also allow cases when the second template argument is present. Those
2667 # cases cannot be handled by std::make_unique:
2668 # return std::unique_ptr<T, U>(foo);
2669 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052670 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532671 return_construct_result = return_construct_pattern.search(line)
2672 if return_construct_result and not HasMoreThanOneArg(
2673 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052674 problems_constructor.append(
2675 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102676 # Disallow:
2677 # std::unique_ptr<T>()
2678 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052679 problems_nullptr.append(
2680 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2681
2682 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162683 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052684 errors.append(output_api.PresubmitError(
2685 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162686 problems_nullptr))
2687 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052688 errors.append(output_api.PresubmitError(
2689 'The following files use explicit std::unique_ptr constructor.'
2690 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162691 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102692 return errors
2693
2694
[email protected]999261d2014-03-03 20:08:082695def _CheckUserActionUpdate(input_api, output_api):
2696 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522697 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082698 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522699 # If actions.xml is already included in the changelist, the PRESUBMIT
2700 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082701 return []
2702
[email protected]999261d2014-03-03 20:08:082703 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2704 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522705 current_actions = None
[email protected]999261d2014-03-03 20:08:082706 for f in input_api.AffectedFiles(file_filter=file_filter):
2707 for line_num, line in f.ChangedContents():
2708 match = input_api.re.search(action_re, line)
2709 if match:
[email protected]2f92dec2014-03-07 19:21:522710 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2711 # loaded only once.
2712 if not current_actions:
2713 with open('tools/metrics/actions/actions.xml') as actions_f:
2714 current_actions = actions_f.read()
2715 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082716 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522717 action = 'name="{0}"'.format(action_name)
2718 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082719 return [output_api.PresubmitPromptWarning(
2720 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522721 'tools/metrics/actions/actions.xml. Please run '
2722 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082723 % (f.LocalPath(), line_num, action_name))]
2724 return []
2725
2726
Daniel Cheng13ca61a882017-08-25 15:11:252727def _ImportJSONCommentEater(input_api):
2728 import sys
2729 sys.path = sys.path + [input_api.os_path.join(
2730 input_api.PresubmitLocalPath(),
2731 'tools', 'json_comment_eater')]
2732 import json_comment_eater
2733 return json_comment_eater
2734
2735
[email protected]99171a92014-06-03 08:44:472736def _GetJSONParseError(input_api, filename, eat_comments=True):
2737 try:
2738 contents = input_api.ReadFile(filename)
2739 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252740 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132741 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472742
2743 input_api.json.loads(contents)
2744 except ValueError as e:
2745 return e
2746 return None
2747
2748
2749def _GetIDLParseError(input_api, filename):
2750 try:
2751 contents = input_api.ReadFile(filename)
2752 idl_schema = input_api.os_path.join(
2753 input_api.PresubmitLocalPath(),
2754 'tools', 'json_schema_compiler', 'idl_schema.py')
2755 process = input_api.subprocess.Popen(
2756 [input_api.python_executable, idl_schema],
2757 stdin=input_api.subprocess.PIPE,
2758 stdout=input_api.subprocess.PIPE,
2759 stderr=input_api.subprocess.PIPE,
2760 universal_newlines=True)
2761 (_, error) = process.communicate(input=contents)
2762 return error or None
2763 except ValueError as e:
2764 return e
2765
2766
2767def _CheckParseErrors(input_api, output_api):
2768 """Check that IDL and JSON files do not contain syntax errors."""
2769 actions = {
2770 '.idl': _GetIDLParseError,
2771 '.json': _GetJSONParseError,
2772 }
[email protected]99171a92014-06-03 08:44:472773 # Most JSON files are preprocessed and support comments, but these do not.
2774 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042775 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472776 ]
2777 # Only run IDL checker on files in these directories.
2778 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042779 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2780 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472781 ]
2782
2783 def get_action(affected_file):
2784 filename = affected_file.LocalPath()
2785 return actions.get(input_api.os_path.splitext(filename)[1])
2786
[email protected]99171a92014-06-03 08:44:472787 def FilterFile(affected_file):
2788 action = get_action(affected_file)
2789 if not action:
2790 return False
2791 path = affected_file.LocalPath()
2792
Erik Staab2dd72b12020-04-16 15:03:402793 if _MatchesFile(input_api,
2794 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2795 path):
[email protected]99171a92014-06-03 08:44:472796 return False
2797
2798 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162799 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472800 return False
2801 return True
2802
2803 results = []
2804 for affected_file in input_api.AffectedFiles(
2805 file_filter=FilterFile, include_deletes=False):
2806 action = get_action(affected_file)
2807 kwargs = {}
2808 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162809 _MatchesFile(input_api, json_no_comments_patterns,
2810 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472811 kwargs['eat_comments'] = False
2812 parse_error = action(input_api,
2813 affected_file.AbsoluteLocalPath(),
2814 **kwargs)
2815 if parse_error:
2816 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2817 (affected_file.LocalPath(), parse_error)))
2818 return results
2819
2820
[email protected]760deea2013-12-10 19:33:492821def _CheckJavaStyle(input_api, output_api):
2822 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472823 import sys
[email protected]760deea2013-12-10 19:33:492824 original_sys_path = sys.path
2825 try:
2826 sys.path = sys.path + [input_api.os_path.join(
2827 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2828 import checkstyle
2829 finally:
2830 # Restore sys.path to what it was before.
2831 sys.path = original_sys_path
2832
2833 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092834 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512835 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492836
2837
Nate Fischerdfd9812e2019-07-18 22:03:002838def _CheckPythonDevilInit(input_api, output_api):
2839 """Checks to make sure devil is initialized correctly in python scripts."""
2840 script_common_initialize_pattern = input_api.re.compile(
2841 r'script_common\.InitializeEnvironment\(')
2842 devil_env_config_initialize = input_api.re.compile(
2843 r'devil_env\.config\.Initialize\(')
2844
2845 errors = []
2846
2847 sources = lambda affected_file: input_api.FilterSourceFile(
2848 affected_file,
2849 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2850 (r'^build[\\/]android[\\/]devil_chromium\.py',
2851 r'^third_party[\\/].*',)),
2852 white_list=[r'.*\.py$'])
2853
2854 for f in input_api.AffectedSourceFiles(sources):
2855 for line_num, line in f.ChangedContents():
2856 if (script_common_initialize_pattern.search(line) or
2857 devil_env_config_initialize.search(line)):
2858 errors.append("%s:%d" % (f.LocalPath(), line_num))
2859
2860 results = []
2861
2862 if errors:
2863 results.append(output_api.PresubmitError(
2864 'Devil initialization should always be done using '
2865 'devil_chromium.Initialize() in the chromium project, to use better '
2866 'defaults for dependencies (ex. up-to-date version of adb).',
2867 errors))
2868
2869 return results
2870
2871
Sean Kau46e29bc2017-08-28 16:31:162872def _MatchesFile(input_api, patterns, path):
2873 for pattern in patterns:
2874 if input_api.re.search(pattern, path):
2875 return True
2876 return False
2877
2878
Daniel Cheng7052cdf2017-11-21 19:23:292879def _GetOwnersFilesToCheckForIpcOwners(input_api):
2880 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172881
Daniel Cheng7052cdf2017-11-21 19:23:292882 Returns:
2883 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2884 contain to cover IPC-related files with noparent reviewer rules.
2885 """
2886 # Whether or not a file affects IPC is (mostly) determined by a simple list
2887 # of filename patterns.
dchenge07de812016-06-20 19:27:172888 file_patterns = [
palmerb19a0932017-01-24 04:00:312889 # Legacy IPC:
dchenge07de812016-06-20 19:27:172890 '*_messages.cc',
2891 '*_messages*.h',
2892 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312893 # Mojo IPC:
dchenge07de812016-06-20 19:27:172894 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472895 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172896 '*_struct_traits*.*',
2897 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312898 '*.typemap',
2899 # Android native IPC:
2900 '*.aidl',
2901 # Blink uses a different file naming convention:
2902 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472903 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172904 '*StructTraits*.*',
2905 '*TypeConverter*.*',
2906 ]
2907
scottmg7a6ed5ba2016-11-04 18:22:042908 # These third_party directories do not contain IPCs, but contain files
2909 # matching the above patterns, which trigger false positives.
2910 exclude_paths = [
2911 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162912 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232913 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292914 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542915 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162916 # These files are just used to communicate between class loaders running
2917 # in the same process.
2918 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572919 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2920
scottmg7a6ed5ba2016-11-04 18:22:042921 ]
2922
dchenge07de812016-06-20 19:27:172923 # Dictionary mapping an OWNERS file path to Patterns.
2924 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2925 # rules ) to a PatternEntry.
2926 # PatternEntry is a dictionary with two keys:
2927 # - 'files': the files that are matched by this pattern
2928 # - 'rules': the per-file rules needed for this pattern
2929 # For example, if we expect OWNERS file to contain rules for *.mojom and
2930 # *_struct_traits*.*, Patterns might look like this:
2931 # {
2932 # '*.mojom': {
2933 # 'files': ...,
2934 # 'rules': [
2935 # 'per-file *.mojom=set noparent',
2936 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2937 # ],
2938 # },
2939 # '*_struct_traits*.*': {
2940 # 'files': ...,
2941 # 'rules': [
2942 # 'per-file *_struct_traits*.*=set noparent',
2943 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2944 # ],
2945 # },
2946 # }
2947 to_check = {}
2948
Daniel Cheng13ca61a882017-08-25 15:11:252949 def AddPatternToCheck(input_file, pattern):
2950 owners_file = input_api.os_path.join(
2951 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2952 if owners_file not in to_check:
2953 to_check[owners_file] = {}
2954 if pattern not in to_check[owners_file]:
2955 to_check[owners_file][pattern] = {
2956 'files': [],
2957 'rules': [
2958 'per-file %s=set noparent' % pattern,
2959 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2960 ]
2961 }
Vaclav Brozekd5de76a2018-03-17 07:57:502962 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252963
dchenge07de812016-06-20 19:27:172964 # Iterate through the affected files to see what we actually need to check
2965 # for. We should only nag patch authors about per-file rules if a file in that
2966 # directory would match that pattern. If a directory only contains *.mojom
2967 # files and no *_messages*.h files, we should only nag about rules for
2968 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252969 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262970 # Manifest files don't have a strong naming convention. Instead, try to find
2971 # affected .cc and .h files which look like they contain a manifest
2972 # definition.
2973 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2974 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2975 if (manifest_pattern.search(f.LocalPath()) and not
2976 test_manifest_pattern.search(f.LocalPath())):
2977 # We expect all actual service manifest files to contain at least one
2978 # qualified reference to service_manager::Manifest.
2979 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252980 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172981 for pattern in file_patterns:
2982 if input_api.fnmatch.fnmatch(
2983 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042984 skip = False
2985 for exclude in exclude_paths:
2986 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2987 skip = True
2988 break
2989 if skip:
2990 continue
Daniel Cheng13ca61a882017-08-25 15:11:252991 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172992 break
2993
Daniel Cheng7052cdf2017-11-21 19:23:292994 return to_check
2995
2996
Wez17c66962020-04-29 15:26:032997def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2998 """Adds OWNERS files to check for correct Fuchsia security owners."""
2999
3000 file_patterns = [
3001 # Component specifications.
3002 '*.cml', # Component Framework v2.
3003 '*.cmx', # Component Framework v1.
3004
3005 # Fuchsia IDL protocol specifications.
3006 '*.fidl',
3007 ]
3008
3009 def AddPatternToCheck(input_file, pattern):
3010 owners_file = input_api.os_path.join(
3011 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3012 if owners_file not in to_check:
3013 to_check[owners_file] = {}
3014 if pattern not in to_check[owners_file]:
3015 to_check[owners_file][pattern] = {
3016 'files': [],
3017 'rules': [
3018 'per-file %s=set noparent' % pattern,
3019 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3020 ]
3021 }
3022 to_check[owners_file][pattern]['files'].append(input_file)
3023
3024 # Iterate through the affected files to see what we actually need to check
3025 # for. We should only nag patch authors about per-file rules if a file in that
3026 # directory would match that pattern.
3027 for f in input_api.AffectedFiles(include_deletes=False):
3028 for pattern in file_patterns:
3029 if input_api.fnmatch.fnmatch(
3030 input_api.os_path.basename(f.LocalPath()), pattern):
3031 AddPatternToCheck(f, pattern)
3032 break
3033
3034 return to_check
3035
3036
3037def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293038 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3039 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033040 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293041
3042 if to_check:
3043 # If there are any OWNERS files to check, there are IPC-related changes in
3044 # this CL. Auto-CC the review list.
3045 output_api.AppendCC('[email protected]')
3046
3047 # Go through the OWNERS files to check, filtering out rules that are already
3048 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173049 for owners_file, patterns in to_check.iteritems():
3050 try:
3051 with file(owners_file) as f:
3052 lines = set(f.read().splitlines())
3053 for entry in patterns.itervalues():
3054 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3055 ]
3056 except IOError:
3057 # No OWNERS file, so all the rules are definitely missing.
3058 continue
3059
3060 # All the remaining lines weren't found in OWNERS files, so emit an error.
3061 errors = []
3062 for owners_file, patterns in to_check.iteritems():
3063 missing_lines = []
3064 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503065 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173066 missing_lines.extend(entry['rules'])
3067 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3068 if missing_lines:
3069 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053070 'Because of the presence of files:\n%s\n\n'
3071 '%s needs the following %d lines added:\n\n%s' %
3072 ('\n'.join(files), owners_file, len(missing_lines),
3073 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173074
3075 results = []
3076 if errors:
vabrf5ce3bf92016-07-11 14:52:413077 if input_api.is_committing:
3078 output = output_api.PresubmitError
3079 else:
3080 output = output_api.PresubmitPromptWarning
3081 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593082 'Found OWNERS files that need to be updated for IPC security ' +
3083 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173084 long_text='\n\n'.join(errors)))
3085
3086 return results
3087
3088
Robert Sesek2c905332020-05-06 23:17:133089def _GetFilesUsingSecurityCriticalFunctions(input_api):
3090 """Checks affected files for changes to security-critical calls. This
3091 function checks the full change diff, to catch both additions/changes
3092 and removals.
3093
3094 Returns a dict keyed by file name, and the value is a set of detected
3095 functions.
3096 """
3097 # Map of function pretty name (displayed in an error) to the pattern to
3098 # match it with.
3099 _PATTERNS_TO_CHECK = {
3100 'content::ServiceProcessHost::LaunchOptions::WithSandboxType':
3101 'WithSandboxType\\('
3102 }
3103 _PATTERNS_TO_CHECK = {
3104 k: input_api.re.compile(v)
3105 for k, v in _PATTERNS_TO_CHECK.items()
3106 }
3107
3108 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3109 files_to_functions = {}
3110 for f in input_api.AffectedFiles():
3111 diff = f.GenerateScmDiff()
3112 for line in diff.split('\n'):
3113 # Not using just RightHandSideLines() because removing a
3114 # call to a security-critical function can be just as important
3115 # as adding or changing the arguments.
3116 if line.startswith('-') or (line.startswith('+') and
3117 not line.startswith('++')):
3118 for name, pattern in _PATTERNS_TO_CHECK.items():
3119 if pattern.search(line):
3120 path = f.LocalPath()
3121 if not path in files_to_functions:
3122 files_to_functions[path] = set()
3123 files_to_functions[path].add(name)
3124 return files_to_functions
3125
3126
3127def _CheckSecurityChanges(input_api, output_api):
3128 """Checks that changes involving security-critical functions are reviewed
3129 by the security team.
3130 """
3131 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3132 if len(files_to_functions):
3133 owners_db = input_api.owners_db
3134 owner_email, reviewers = (
3135 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3136 input_api,
3137 owners_db.email_regexp,
3138 approval_needed=input_api.is_committing))
3139
3140 # Load the OWNERS file for security changes.
3141 owners_file = 'ipc/SECURITY_OWNERS'
3142 security_owners = owners_db.owners_rooted_at_file(owners_file)
3143
3144 has_security_owner = any([owner in reviewers for owner in security_owners])
3145 if not has_security_owner:
3146 msg = 'The following files change calls to security-sensive functions\n' \
3147 'that need to be reviewed by {}.\n'.format(owners_file)
3148 for path, names in files_to_functions.items():
3149 msg += ' {}\n'.format(path)
3150 for name in names:
3151 msg += ' {}\n'.format(name)
3152 msg += '\n'
3153
3154 if input_api.is_committing:
3155 output = output_api.PresubmitError
3156 else:
3157 output = output_api.PresubmitNotifyResult
3158 return [output(msg)]
3159
3160 return []
3161
3162
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263163def _CheckSetNoParent(input_api, output_api):
3164 """Checks that set noparent is only used together with an OWNERS file in
3165 //build/OWNERS.setnoparent (see also
3166 //docs/code_reviews.md#owners-files-details)
3167 """
3168 errors = []
3169
3170 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3171 allowed_owners_files = set()
3172 with open(allowed_owners_files_file, 'r') as f:
3173 for line in f:
3174 line = line.strip()
3175 if not line or line.startswith('#'):
3176 continue
3177 allowed_owners_files.add(line)
3178
3179 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3180
3181 for f in input_api.AffectedFiles(include_deletes=False):
3182 if not f.LocalPath().endswith('OWNERS'):
3183 continue
3184
3185 found_owners_files = set()
3186 found_set_noparent_lines = dict()
3187
3188 # Parse the OWNERS file.
3189 for lineno, line in enumerate(f.NewContents(), 1):
3190 line = line.strip()
3191 if line.startswith('set noparent'):
3192 found_set_noparent_lines[''] = lineno
3193 if line.startswith('file://'):
3194 if line in allowed_owners_files:
3195 found_owners_files.add('')
3196 if line.startswith('per-file'):
3197 match = per_file_pattern.match(line)
3198 if match:
3199 glob = match.group(1).strip()
3200 directive = match.group(2).strip()
3201 if directive == 'set noparent':
3202 found_set_noparent_lines[glob] = lineno
3203 if directive.startswith('file://'):
3204 if directive in allowed_owners_files:
3205 found_owners_files.add(glob)
3206
3207 # Check that every set noparent line has a corresponding file:// line
3208 # listed in build/OWNERS.setnoparent.
3209 for set_noparent_line in found_set_noparent_lines:
3210 if set_noparent_line in found_owners_files:
3211 continue
3212 errors.append(' %s:%d' % (f.LocalPath(),
3213 found_set_noparent_lines[set_noparent_line]))
3214
3215 results = []
3216 if errors:
3217 if input_api.is_committing:
3218 output = output_api.PresubmitError
3219 else:
3220 output = output_api.PresubmitPromptWarning
3221 results.append(output(
3222 'Found the following "set noparent" restrictions in OWNERS files that '
3223 'do not include owners from build/OWNERS.setnoparent:',
3224 long_text='\n\n'.join(errors)))
3225 return results
3226
3227
jbriance9e12f162016-11-25 07:57:503228def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313229 """Checks that added or removed lines in non third party affected
3230 header files do not lead to new useless class or struct forward
3231 declaration.
jbriance9e12f162016-11-25 07:57:503232 """
3233 results = []
3234 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3235 input_api.re.MULTILINE)
3236 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3237 input_api.re.MULTILINE)
3238 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313239 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193240 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493241 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313242 continue
3243
jbriance9e12f162016-11-25 07:57:503244 if not f.LocalPath().endswith('.h'):
3245 continue
3246
3247 contents = input_api.ReadFile(f)
3248 fwd_decls = input_api.re.findall(class_pattern, contents)
3249 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3250
3251 useless_fwd_decls = []
3252 for decl in fwd_decls:
3253 count = sum(1 for _ in input_api.re.finditer(
3254 r'\b%s\b' % input_api.re.escape(decl), contents))
3255 if count == 1:
3256 useless_fwd_decls.append(decl)
3257
3258 if not useless_fwd_decls:
3259 continue
3260
3261 for line in f.GenerateScmDiff().splitlines():
3262 if (line.startswith('-') and not line.startswith('--') or
3263 line.startswith('+') and not line.startswith('++')):
3264 for decl in useless_fwd_decls:
3265 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3266 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243267 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503268 (f.LocalPath(), decl)))
3269 useless_fwd_decls.remove(decl)
3270
3271 return results
3272
Jinsong Fan91ebbbd2019-04-16 14:57:173273def _CheckAndroidDebuggableBuild(input_api, output_api):
3274 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3275 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3276 this is a debuggable build of Android.
3277 """
3278 build_type_check_pattern = input_api.re.compile(
3279 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3280
3281 errors = []
3282
3283 sources = lambda affected_file: input_api.FilterSourceFile(
3284 affected_file,
3285 black_list=(_EXCLUDED_PATHS +
3286 _TEST_CODE_EXCLUDED_PATHS +
3287 input_api.DEFAULT_BLACK_LIST +
3288 (r"^android_webview[\\/]support_library[\\/]"
3289 "boundary_interfaces[\\/]",
3290 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3291 r'^third_party[\\/].*',
3292 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3293 r"webview[\\/]chromium[\\/]License.*",)),
3294 white_list=[r'.*\.java$'])
3295
3296 for f in input_api.AffectedSourceFiles(sources):
3297 for line_num, line in f.ChangedContents():
3298 if build_type_check_pattern.search(line):
3299 errors.append("%s:%d" % (f.LocalPath(), line_num))
3300
3301 results = []
3302
3303 if errors:
3304 results.append(output_api.PresubmitPromptWarning(
3305 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3306 ' Please use BuildInfo.isDebugAndroid() instead.',
3307 errors))
3308
3309 return results
jbriance9e12f162016-11-25 07:57:503310
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493311# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293312def _CheckAndroidToastUsage(input_api, output_api):
3313 """Checks that code uses org.chromium.ui.widget.Toast instead of
3314 android.widget.Toast (Chromium Toast doesn't force hardware
3315 acceleration on low-end devices, saving memory).
3316 """
3317 toast_import_pattern = input_api.re.compile(
3318 r'^import android\.widget\.Toast;$')
3319
3320 errors = []
3321
3322 sources = lambda affected_file: input_api.FilterSourceFile(
3323 affected_file,
3324 black_list=(_EXCLUDED_PATHS +
3325 _TEST_CODE_EXCLUDED_PATHS +
3326 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043327 (r'^chromecast[\\/].*',
3328 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493329 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293330
3331 for f in input_api.AffectedSourceFiles(sources):
3332 for line_num, line in f.ChangedContents():
3333 if toast_import_pattern.search(line):
3334 errors.append("%s:%d" % (f.LocalPath(), line_num))
3335
3336 results = []
3337
3338 if errors:
3339 results.append(output_api.PresubmitError(
3340 'android.widget.Toast usage is detected. Android toasts use hardware'
3341 ' acceleration, and can be\ncostly on low-end devices. Please use'
3342 ' org.chromium.ui.widget.Toast instead.\n'
3343 'Contact [email protected] if you have any questions.',
3344 errors))
3345
3346 return results
3347
3348
dgnaa68d5e2015-06-10 10:08:223349def _CheckAndroidCrLogUsage(input_api, output_api):
3350 """Checks that new logs using org.chromium.base.Log:
3351 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513352 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223353 """
pkotwicza1dd0b002016-05-16 14:41:043354
torne89540622017-03-24 19:41:303355 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043356 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303357 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043358 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303359 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043360 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3361 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093362 # The customtabs_benchmark is a small app that does not depend on Chromium
3363 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043364 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043365 ]
3366
dgnaa68d5e2015-06-10 10:08:223367 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123368 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3369 class_in_base_pattern = input_api.re.compile(
3370 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3371 has_some_log_import_pattern = input_api.re.compile(
3372 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223373 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553374 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223375 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463376 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553377 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223378
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463379 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493380 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043381 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123382
dgnaa68d5e2015-06-10 10:08:223383 tag_decl_errors = []
3384 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123385 tag_errors = []
dgn38736db2015-09-18 19:20:513386 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123387 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223388
3389 for f in input_api.AffectedSourceFiles(sources):
3390 file_content = input_api.ReadFile(f)
3391 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223392 # Per line checks
dgn87d9fb62015-06-12 09:15:123393 if (cr_log_import_pattern.search(file_content) or
3394 (class_in_base_pattern.search(file_content) and
3395 not has_some_log_import_pattern.search(file_content))):
3396 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223397 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553398 if rough_log_decl_pattern.search(line):
3399 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223400
3401 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123402 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223403 if match:
3404 has_modified_logs = True
3405
3406 # Make sure it uses "TAG"
3407 if not match.group('tag') == 'TAG':
3408 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123409 else:
3410 # Report non cr Log function calls in changed lines
3411 for line_num, line in f.ChangedContents():
3412 if log_call_pattern.search(line):
3413 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223414
3415 # Per file checks
3416 if has_modified_logs:
3417 # Make sure the tag is using the "cr" prefix and is not too long
3418 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513419 tag_name = match.group('name') if match else None
3420 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223421 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513422 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223423 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513424 elif '.' in tag_name:
3425 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223426
3427 results = []
3428 if tag_decl_errors:
3429 results.append(output_api.PresubmitPromptWarning(
3430 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513431 '"private static final String TAG = "<package tag>".\n'
3432 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223433 tag_decl_errors))
3434
3435 if tag_length_errors:
3436 results.append(output_api.PresubmitError(
3437 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513438 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223439 tag_length_errors))
3440
3441 if tag_errors:
3442 results.append(output_api.PresubmitPromptWarning(
3443 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3444 tag_errors))
3445
dgn87d9fb62015-06-12 09:15:123446 if util_log_errors:
dgn4401aa52015-04-29 16:26:173447 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123448 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3449 util_log_errors))
3450
dgn38736db2015-09-18 19:20:513451 if tag_with_dot_errors:
3452 results.append(output_api.PresubmitPromptWarning(
3453 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3454 tag_with_dot_errors))
3455
dgn4401aa52015-04-29 16:26:173456 return results
3457
3458
Yoland Yanb92fa522017-08-28 17:37:063459def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3460 """Checks that junit.framework.* is no longer used."""
3461 deprecated_junit_framework_pattern = input_api.re.compile(
3462 r'^import junit\.framework\..*;',
3463 input_api.re.MULTILINE)
3464 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493465 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063466 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133467 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063468 for line_num, line in f.ChangedContents():
3469 if deprecated_junit_framework_pattern.search(line):
3470 errors.append("%s:%d" % (f.LocalPath(), line_num))
3471
3472 results = []
3473 if errors:
3474 results.append(output_api.PresubmitError(
3475 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3476 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3477 ' if you have any question.', errors))
3478 return results
3479
3480
3481def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3482 """Checks that if new Java test classes have inheritance.
3483 Either the new test class is JUnit3 test or it is a JUnit4 test class
3484 with a base class, either case is undesirable.
3485 """
3486 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3487
3488 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493489 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063490 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133491 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063492 if not f.OldContents():
3493 class_declaration_start_flag = False
3494 for line_num, line in f.ChangedContents():
3495 if class_declaration_pattern.search(line):
3496 class_declaration_start_flag = True
3497 if class_declaration_start_flag and ' extends ' in line:
3498 errors.append('%s:%d' % (f.LocalPath(), line_num))
3499 if '{' in line:
3500 class_declaration_start_flag = False
3501
3502 results = []
3503 if errors:
3504 results.append(output_api.PresubmitPromptWarning(
3505 'The newly created files include Test classes that inherits from base'
3506 ' class. Please do not use inheritance in JUnit4 tests or add new'
3507 ' JUnit3 tests. Contact [email protected] if you have any'
3508 ' questions.', errors))
3509 return results
3510
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203511
yolandyan45001472016-12-21 21:12:423512def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3513 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3514 deprecated_annotation_import_pattern = input_api.re.compile(
3515 r'^import android\.test\.suitebuilder\.annotation\..*;',
3516 input_api.re.MULTILINE)
3517 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493518 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423519 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133520 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423521 for line_num, line in f.ChangedContents():
3522 if deprecated_annotation_import_pattern.search(line):
3523 errors.append("%s:%d" % (f.LocalPath(), line_num))
3524
3525 results = []
3526 if errors:
3527 results.append(output_api.PresubmitError(
3528 'Annotations in android.test.suitebuilder.annotation have been'
3529 ' deprecated since API level 24. Please use android.support.test.filters'
3530 ' from //third_party/android_support_test_runner:runner_java instead.'
3531 ' Contact [email protected] if you have any questions.', errors))
3532 return results
3533
3534
agrieve7b6479d82015-10-07 14:24:223535def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3536 """Checks if MDPI assets are placed in a correct directory."""
3537 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3538 ('/res/drawable/' in f.LocalPath() or
3539 '/res/drawable-ldrtl/' in f.LocalPath()))
3540 errors = []
3541 for f in input_api.AffectedFiles(include_deletes=False,
3542 file_filter=file_filter):
3543 errors.append(' %s' % f.LocalPath())
3544
3545 results = []
3546 if errors:
3547 results.append(output_api.PresubmitError(
3548 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3549 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3550 '/res/drawable-ldrtl/.\n'
3551 'Contact [email protected] if you have questions.', errors))
3552 return results
3553
3554
Nate Fischer535972b2017-09-16 01:06:183555def _CheckAndroidWebkitImports(input_api, output_api):
3556 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353557 android.webview.ValueCallback except in the WebView glue layer
3558 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183559 """
3560 valuecallback_import_pattern = input_api.re.compile(
3561 r'^import android\.webkit\.ValueCallback;$')
3562
3563 errors = []
3564
3565 sources = lambda affected_file: input_api.FilterSourceFile(
3566 affected_file,
3567 black_list=(_EXCLUDED_PATHS +
3568 _TEST_CODE_EXCLUDED_PATHS +
3569 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353570 (r'^android_webview[\\/]glue[\\/].*',
3571 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493572 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183573
3574 for f in input_api.AffectedSourceFiles(sources):
3575 for line_num, line in f.ChangedContents():
3576 if valuecallback_import_pattern.search(line):
3577 errors.append("%s:%d" % (f.LocalPath(), line_num))
3578
3579 results = []
3580
3581 if errors:
3582 results.append(output_api.PresubmitError(
3583 'android.webkit.ValueCallback usage is detected outside of the glue'
3584 ' layer. To stay compatible with the support library, android.webkit.*'
3585 ' classes should only be used inside the glue layer and'
3586 ' org.chromium.base.Callback should be used instead.',
3587 errors))
3588
3589 return results
3590
3591
Becky Zhou7c69b50992018-12-10 19:37:573592def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3593 """Checks Android XML styles """
3594 import sys
3595 original_sys_path = sys.path
3596 try:
3597 sys.path = sys.path + [input_api.os_path.join(
3598 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3599 import checkxmlstyle
3600 finally:
3601 # Restore sys.path to what it was before.
3602 sys.path = original_sys_path
3603
3604 if is_check_on_upload:
3605 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3606 else:
3607 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3608
3609
agrievef32bcc72016-04-04 14:57:403610class PydepsChecker(object):
3611 def __init__(self, input_api, pydeps_files):
3612 self._file_cache = {}
3613 self._input_api = input_api
3614 self._pydeps_files = pydeps_files
3615
3616 def _LoadFile(self, path):
3617 """Returns the list of paths within a .pydeps file relative to //."""
3618 if path not in self._file_cache:
3619 with open(path) as f:
3620 self._file_cache[path] = f.read()
3621 return self._file_cache[path]
3622
3623 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3624 """Returns an interable of paths within the .pydep, relativized to //."""
3625 os_path = self._input_api.os_path
3626 pydeps_dir = os_path.dirname(pydeps_path)
3627 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3628 if not l.startswith('*'))
3629 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3630
3631 def _CreateFilesToPydepsMap(self):
3632 """Returns a map of local_path -> list_of_pydeps."""
3633 ret = {}
3634 for pydep_local_path in self._pydeps_files:
3635 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3636 ret.setdefault(path, []).append(pydep_local_path)
3637 return ret
3638
3639 def ComputeAffectedPydeps(self):
3640 """Returns an iterable of .pydeps files that might need regenerating."""
3641 affected_pydeps = set()
3642 file_to_pydeps_map = None
3643 for f in self._input_api.AffectedFiles(include_deletes=True):
3644 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463645 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3646 # subrepositories. We can't figure out which files change, so re-check
3647 # all files.
3648 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383649 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3650 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403651 return self._pydeps_files
3652 elif local_path.endswith('.pydeps'):
3653 if local_path in self._pydeps_files:
3654 affected_pydeps.add(local_path)
3655 elif local_path.endswith('.py'):
3656 if file_to_pydeps_map is None:
3657 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3658 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3659 return affected_pydeps
3660
3661 def DetermineIfStale(self, pydeps_path):
3662 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413663 import difflib
John Budorick47ca3fe2018-02-10 00:53:103664 import os
3665
agrievef32bcc72016-04-04 14:57:403666 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3667 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:103668 env = dict(os.environ)
3669 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403670 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103671 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413672 old_contents = old_pydeps_data[2:]
3673 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:403674 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:413675 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403676
3677
Tibor Goldschwendt360793f72019-06-25 18:23:493678def _ParseGclientArgs():
3679 args = {}
3680 with open('build/config/gclient_args.gni', 'r') as f:
3681 for line in f:
3682 line = line.strip()
3683 if not line or line.startswith('#'):
3684 continue
3685 attribute, value = line.split('=')
3686 args[attribute.strip()] = value.strip()
3687 return args
3688
3689
agrievef32bcc72016-04-04 14:57:403690def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3691 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403692 # This check is for Python dependency lists (.pydeps files), and involves
3693 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3694 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283695 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003696 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493697 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
agrievef32bcc72016-04-04 14:57:403698 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3699 results = []
3700 # First, check for new / deleted .pydeps.
3701 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033702 # Check whether we are running the presubmit check for a file in src.
3703 # f.LocalPath is relative to repo (src, or internal repo).
3704 # os_path.exists is relative to src repo.
3705 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3706 # to src and we can conclude that the pydeps is in src.
3707 if input_api.os_path.exists(f.LocalPath()):
3708 if f.LocalPath().endswith('.pydeps'):
3709 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3710 results.append(output_api.PresubmitError(
3711 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3712 'remove %s' % f.LocalPath()))
3713 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3714 results.append(output_api.PresubmitError(
3715 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3716 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403717
3718 if results:
3719 return results
3720
3721 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
3722
3723 for pydep_path in checker.ComputeAffectedPydeps():
3724 try:
phajdan.jr0d9878552016-11-04 10:49:413725 result = checker.DetermineIfStale(pydep_path)
3726 if result:
3727 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403728 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413729 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3730 'To regenerate, run:\n\n %s' %
3731 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403732 except input_api.subprocess.CalledProcessError as error:
3733 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3734 long_text=error.output)]
3735
3736 return results
3737
3738
glidere61efad2015-02-18 17:39:433739def _CheckSingletonInHeaders(input_api, output_api):
3740 """Checks to make sure no header files have |Singleton<|."""
3741 def FileFilter(affected_file):
3742 # It's ok for base/memory/singleton.h to have |Singleton<|.
3743 black_list = (_EXCLUDED_PATHS +
3744 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043745 (r"^base[\\/]memory[\\/]singleton\.h$",
3746 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473747 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433748 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3749
sergeyu34d21222015-09-16 00:11:443750 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433751 files = []
3752 for f in input_api.AffectedSourceFiles(FileFilter):
3753 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3754 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3755 contents = input_api.ReadFile(f)
3756 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243757 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433758 pattern.search(line)):
3759 files.append(f)
3760 break
3761
3762 if files:
yolandyandaabc6d2016-04-18 18:29:393763 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443764 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433765 'Please move them to an appropriate source file so that the ' +
3766 'template gets instantiated in a single compilation unit.',
3767 files) ]
3768 return []
3769
3770
[email protected]fd20b902014-05-09 02:14:533771_DEPRECATED_CSS = [
3772 # Values
3773 ( "-webkit-box", "flex" ),
3774 ( "-webkit-inline-box", "inline-flex" ),
3775 ( "-webkit-flex", "flex" ),
3776 ( "-webkit-inline-flex", "inline-flex" ),
3777 ( "-webkit-min-content", "min-content" ),
3778 ( "-webkit-max-content", "max-content" ),
3779
3780 # Properties
3781 ( "-webkit-background-clip", "background-clip" ),
3782 ( "-webkit-background-origin", "background-origin" ),
3783 ( "-webkit-background-size", "background-size" ),
3784 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443785 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533786
3787 # Functions
3788 ( "-webkit-gradient", "gradient" ),
3789 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3790 ( "-webkit-linear-gradient", "linear-gradient" ),
3791 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3792 ( "-webkit-radial-gradient", "radial-gradient" ),
3793 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3794]
3795
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203796
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493797# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243798def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533799 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253800 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343801 documentation and iOS CSS for dom distiller
3802 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253803 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533804 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493805 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253806 black_list = (_EXCLUDED_PATHS +
3807 _TEST_CODE_EXCLUDED_PATHS +
3808 input_api.DEFAULT_BLACK_LIST +
3809 (r"^chrome/common/extensions/docs",
3810 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343811 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443812 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253813 r"^native_client_sdk"))
3814 file_filter = lambda f: input_api.FilterSourceFile(
3815 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533816 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3817 for line_num, line in fpath.ChangedContents():
3818 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023819 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533820 results.append(output_api.PresubmitError(
3821 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3822 (fpath.LocalPath(), line_num, deprecated_value, value)))
3823 return results
3824
mohan.reddyf21db962014-10-16 12:26:473825
rlanday6802cf632017-05-30 17:48:363826def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363827 bad_files = {}
3828 for f in input_api.AffectedFiles(include_deletes=False):
3829 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493830 not f.LocalPath().startswith('third_party/blink') and
3831 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363832 continue
3833
Daniel Bratell65b033262019-04-23 08:17:063834 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363835 continue
3836
Vaclav Brozekd5de76a2018-03-17 07:57:503837 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363838 if "#include" in line and "../" in line]
3839 if not relative_includes:
3840 continue
3841 bad_files[f.LocalPath()] = relative_includes
3842
3843 if not bad_files:
3844 return []
3845
3846 error_descriptions = []
3847 for file_path, bad_lines in bad_files.iteritems():
3848 error_description = file_path
3849 for line in bad_lines:
3850 error_description += '\n ' + line
3851 error_descriptions.append(error_description)
3852
3853 results = []
3854 results.append(output_api.PresubmitError(
3855 'You added one or more relative #include paths (including "../").\n'
3856 'These shouldn\'t be used because they can be used to include headers\n'
3857 'from code that\'s not correctly specified as a dependency in the\n'
3858 'relevant BUILD.gn file(s).',
3859 error_descriptions))
3860
3861 return results
3862
Takeshi Yoshinoe387aa32017-08-02 13:16:133863
Daniel Bratell65b033262019-04-23 08:17:063864def _CheckForCcIncludes(input_api, output_api):
3865 """Check that nobody tries to include a cc file. It's a relatively
3866 common error which results in duplicate symbols in object
3867 files. This may not always break the build until someone later gets
3868 very confusing linking errors."""
3869 results = []
3870 for f in input_api.AffectedFiles(include_deletes=False):
3871 # We let third_party code do whatever it wants
3872 if (f.LocalPath().startswith('third_party') and
3873 not f.LocalPath().startswith('third_party/blink') and
3874 not f.LocalPath().startswith('third_party\\blink')):
3875 continue
3876
3877 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3878 continue
3879
3880 for _, line in f.ChangedContents():
3881 if line.startswith('#include "'):
3882 included_file = line.split('"')[1]
3883 if _IsCPlusPlusFile(input_api, included_file):
3884 # The most common naming for external files with C++ code,
3885 # apart from standard headers, is to call them foo.inc, but
3886 # Chromium sometimes uses foo-inc.cc so allow that as well.
3887 if not included_file.endswith(('.h', '-inc.cc')):
3888 results.append(output_api.PresubmitError(
3889 'Only header files or .inc files should be included in other\n'
3890 'C++ files. Compiling the contents of a cc file more than once\n'
3891 'will cause duplicate information in the build which may later\n'
3892 'result in strange link_errors.\n' +
3893 f.LocalPath() + ':\n ' +
3894 line))
3895
3896 return results
3897
3898
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203899def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3900 if not isinstance(key, ast.Str):
3901 return 'Key at line %d must be a string literal' % key.lineno
3902 if not isinstance(value, ast.Dict):
3903 return 'Value at line %d must be a dict' % value.lineno
3904 if len(value.keys) != 1:
3905 return 'Dict at line %d must have single entry' % value.lineno
3906 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3907 return (
3908 'Entry at line %d must have a string literal \'filepath\' as key' %
3909 value.lineno)
3910 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133911
Takeshi Yoshinoe387aa32017-08-02 13:16:133912
Sergey Ulanov4af16052018-11-08 02:41:463913def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203914 if not isinstance(key, ast.Str):
3915 return 'Key at line %d must be a string literal' % key.lineno
3916 if not isinstance(value, ast.List):
3917 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463918 for element in value.elts:
3919 if not isinstance(element, ast.Str):
3920 return 'Watchlist elements on line %d is not a string' % key.lineno
3921 if not email_regex.match(element.s):
3922 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3923 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203924 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133925
Takeshi Yoshinoe387aa32017-08-02 13:16:133926
Sergey Ulanov4af16052018-11-08 02:41:463927def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203928 mismatch_template = (
3929 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3930 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133931
Sergey Ulanov4af16052018-11-08 02:41:463932 email_regex = input_api.re.compile(
3933 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3934
3935 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203936 i = 0
3937 last_key = ''
3938 while True:
3939 if i >= len(wd_dict.keys):
3940 if i >= len(w_dict.keys):
3941 return None
3942 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3943 elif i >= len(w_dict.keys):
3944 return (
3945 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133946
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203947 wd_key = wd_dict.keys[i]
3948 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133949
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203950 result = _CheckWatchlistDefinitionsEntrySyntax(
3951 wd_key, wd_dict.values[i], ast)
3952 if result is not None:
3953 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133954
Sergey Ulanov4af16052018-11-08 02:41:463955 result = _CheckWatchlistsEntrySyntax(
3956 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203957 if result is not None:
3958 return 'Bad entry in WATCHLISTS dict: %s' % result
3959
3960 if wd_key.s != w_key.s:
3961 return mismatch_template % (
3962 '%s at line %d' % (wd_key.s, wd_key.lineno),
3963 '%s at line %d' % (w_key.s, w_key.lineno))
3964
3965 if wd_key.s < last_key:
3966 return (
3967 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3968 (wd_key.lineno, w_key.lineno))
3969 last_key = wd_key.s
3970
3971 i = i + 1
3972
3973
Sergey Ulanov4af16052018-11-08 02:41:463974def _CheckWATCHLISTSSyntax(expression, input_api):
3975 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976 if not isinstance(expression, ast.Expression):
3977 return 'WATCHLISTS file must contain a valid expression'
3978 dictionary = expression.body
3979 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3980 return 'WATCHLISTS file must have single dict with exactly two entries'
3981
3982 first_key = dictionary.keys[0]
3983 first_value = dictionary.values[0]
3984 second_key = dictionary.keys[1]
3985 second_value = dictionary.values[1]
3986
3987 if (not isinstance(first_key, ast.Str) or
3988 first_key.s != 'WATCHLIST_DEFINITIONS' or
3989 not isinstance(first_value, ast.Dict)):
3990 return (
3991 'The first entry of the dict in WATCHLISTS file must be '
3992 'WATCHLIST_DEFINITIONS dict')
3993
3994 if (not isinstance(second_key, ast.Str) or
3995 second_key.s != 'WATCHLISTS' or
3996 not isinstance(second_value, ast.Dict)):
3997 return (
3998 'The second entry of the dict in WATCHLISTS file must be '
3999 'WATCHLISTS dict')
4000
Sergey Ulanov4af16052018-11-08 02:41:464001 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134002
4003
4004def _CheckWATCHLISTS(input_api, output_api):
4005 for f in input_api.AffectedFiles(include_deletes=False):
4006 if f.LocalPath() == 'WATCHLISTS':
4007 contents = input_api.ReadFile(f, 'r')
4008
4009 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204010 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134011 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204012 # Get an AST tree for it and scan the tree for detailed style checking.
4013 expression = input_api.ast.parse(
4014 contents, filename='WATCHLISTS', mode='eval')
4015 except ValueError as e:
4016 return [output_api.PresubmitError(
4017 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4018 except SyntaxError as e:
4019 return [output_api.PresubmitError(
4020 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4021 except TypeError as e:
4022 return [output_api.PresubmitError(
4023 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134024
Sergey Ulanov4af16052018-11-08 02:41:464025 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204026 if result is not None:
4027 return [output_api.PresubmitError(result)]
4028 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134029
4030 return []
4031
4032
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194033def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4034 """Checks that newly added header files have corresponding GN changes.
4035 Note that this is only a heuristic. To be precise, run script:
4036 build/check_gn_headers.py.
4037 """
4038
4039 def headers(f):
4040 return input_api.FilterSourceFile(
4041 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4042
4043 new_headers = []
4044 for f in input_api.AffectedSourceFiles(headers):
4045 if f.Action() != 'A':
4046 continue
4047 new_headers.append(f.LocalPath())
4048
4049 def gn_files(f):
4050 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4051
4052 all_gn_changed_contents = ''
4053 for f in input_api.AffectedSourceFiles(gn_files):
4054 for _, line in f.ChangedContents():
4055 all_gn_changed_contents += line
4056
4057 problems = []
4058 for header in new_headers:
4059 basename = input_api.os_path.basename(header)
4060 if basename not in all_gn_changed_contents:
4061 problems.append(header)
4062
4063 if problems:
4064 return [output_api.PresubmitPromptWarning(
4065 'Missing GN changes for new header files', items=sorted(problems),
4066 long_text='Please double check whether newly added header files need '
4067 'corresponding changes in gn or gni files.\nThis checking is only a '
4068 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4069 'Read https://crbug.com/661774 for more info.')]
4070 return []
4071
4072
Michael Giuffridad3bc8672018-10-25 22:48:024073def _CheckCorrectProductNameInMessages(input_api, output_api):
4074 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4075
4076 This assumes we won't intentionally reference one product from the other
4077 product.
4078 """
4079 all_problems = []
4080 test_cases = [{
4081 "filename_postfix": "google_chrome_strings.grd",
4082 "correct_name": "Chrome",
4083 "incorrect_name": "Chromium",
4084 }, {
4085 "filename_postfix": "chromium_strings.grd",
4086 "correct_name": "Chromium",
4087 "incorrect_name": "Chrome",
4088 }]
4089
4090 for test_case in test_cases:
4091 problems = []
4092 filename_filter = lambda x: x.LocalPath().endswith(
4093 test_case["filename_postfix"])
4094
4095 # Check each new line. Can yield false positives in multiline comments, but
4096 # easier than trying to parse the XML because messages can have nested
4097 # children, and associating message elements with affected lines is hard.
4098 for f in input_api.AffectedSourceFiles(filename_filter):
4099 for line_num, line in f.ChangedContents():
4100 if "<message" in line or "<!--" in line or "-->" in line:
4101 continue
4102 if test_case["incorrect_name"] in line:
4103 problems.append(
4104 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4105
4106 if problems:
4107 message = (
4108 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4109 % (test_case["correct_name"], test_case["correct_name"],
4110 test_case["incorrect_name"]))
4111 all_problems.append(
4112 output_api.PresubmitPromptWarning(message, items=problems))
4113
4114 return all_problems
4115
4116
Dirk Pranke3c18a382019-03-15 01:07:514117def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4118 # TODO(crbug.com/941824): We need to make sure the entries in
4119 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4120 # so that users of //buildtools in other projects get the same tooling
4121 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4122 # support to gclient, we can eliminate the duplication and delete
4123 # this presubmit check.
4124
4125 # Update this regexp if new revisions are added to the files.
4126 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264127 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514128
4129 # If a user is changing one revision, they need to change the same
4130 # line in both files. This means that any given change should contain
4131 # exactly the same list of changed lines that match the regexps. The
4132 # replace(' ', '') call allows us to ignore whitespace changes to the
4133 # lines. The 'long_text' parameter to the error will contain the
4134 # list of changed lines in both files, which should make it easy enough
4135 # to spot the error without going overboard in this implementation.
4136 revs_changes = {
4137 'DEPS': {},
4138 'buildtools/DEPS': {},
4139 }
4140 long_text = ''
4141
4142 for f in input_api.AffectedFiles(
4143 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4144 for line_num, line in f.ChangedContents():
4145 if rev_regexp.search(line):
4146 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4147 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4148
4149 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4150 return [output_api.PresubmitError(
4151 'Change buildtools revisions in sync in both //DEPS and '
4152 '//buildtools/DEPS.', long_text=long_text + '\n')]
4153 else:
4154 return []
4155
4156
Daniel Bratell93eb6c62019-04-29 20:13:364157def _CheckForTooLargeFiles(input_api, output_api):
4158 """Avoid large files, especially binary files, in the repository since
4159 git doesn't scale well for those. They will be in everyone's repo
4160 clones forever, forever making Chromium slower to clone and work
4161 with."""
4162
4163 # Uploading files to cloud storage is not trivial so we don't want
4164 # to set the limit too low, but the upper limit for "normal" large
4165 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4166 # anything over 20 MB is exceptional.
4167 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4168
4169 too_large_files = []
4170 for f in input_api.AffectedFiles():
4171 # Check both added and modified files (but not deleted files).
4172 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384173 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364174 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4175 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4176
4177 if too_large_files:
4178 message = (
4179 'Do not commit large files to git since git scales badly for those.\n' +
4180 'Instead put the large files in cloud storage and use DEPS to\n' +
4181 'fetch them.\n' + '\n'.join(too_large_files)
4182 )
4183 return [output_api.PresubmitError(
4184 'Too large files found in commit', long_text=message + '\n')]
4185 else:
4186 return []
4187
Max Morozb47503b2019-08-08 21:03:274188
4189def _CheckFuzzTargets(input_api, output_api):
4190 """Checks specific for fuzz target sources."""
4191 EXPORTED_SYMBOLS = [
4192 'LLVMFuzzerInitialize',
4193 'LLVMFuzzerCustomMutator',
4194 'LLVMFuzzerCustomCrossOver',
4195 'LLVMFuzzerMutate',
4196 ]
4197
4198 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4199
4200 def FilterFile(affected_file):
4201 """Ignore libFuzzer source code."""
4202 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4203 black_list = r"^third_party[\\/]libFuzzer"
4204
4205 return input_api.FilterSourceFile(
4206 affected_file,
4207 white_list=[white_list],
4208 black_list=[black_list])
4209
4210 files_with_missing_header = []
4211 for f in input_api.AffectedSourceFiles(FilterFile):
4212 contents = input_api.ReadFile(f, 'r')
4213 if REQUIRED_HEADER in contents:
4214 continue
4215
4216 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4217 files_with_missing_header.append(f.LocalPath())
4218
4219 if not files_with_missing_header:
4220 return []
4221
4222 long_text = (
4223 'If you define any of the libFuzzer optional functions (%s), it is '
4224 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4225 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4226 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4227 'to access command line arguments passed to the fuzzer. Instead, prefer '
4228 'static initialization and shared resources as documented in '
4229 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4230 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4231 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4232 )
4233
4234 return [output_api.PresubmitPromptWarning(
4235 message="Missing '%s' in:" % REQUIRED_HEADER,
4236 items=files_with_missing_header,
4237 long_text=long_text)]
4238
4239
Mohamed Heikald048240a2019-11-12 16:57:374240def _CheckNewImagesWarning(input_api, output_api):
4241 """
4242 Warns authors who add images into the repo to make sure their images are
4243 optimized before committing.
4244 """
4245 images_added = False
4246 image_paths = []
4247 errors = []
4248 filter_lambda = lambda x: input_api.FilterSourceFile(
4249 x,
4250 black_list=(('(?i).*test', r'.*\/junit\/')
4251 + input_api.DEFAULT_BLACK_LIST),
4252 white_list=[r'.*\/(drawable|mipmap)' ]
4253 )
4254 for f in input_api.AffectedFiles(
4255 include_deletes=False, file_filter=filter_lambda):
4256 local_path = f.LocalPath().lower()
4257 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4258 images_added = True
4259 image_paths.append(f)
4260 if images_added:
4261 errors.append(output_api.PresubmitPromptWarning(
4262 'It looks like you are trying to commit some images. If these are '
4263 'non-test-only images, please make sure to read and apply the tips in '
4264 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4265 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4266 'FYI only and will not block your CL on the CQ.', image_paths))
4267 return errors
4268
4269
dgnaa68d5e2015-06-10 10:08:224270def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574271 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224272 results = []
dgnaa68d5e2015-06-10 10:08:224273 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174274 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224275 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294276 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064277 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4278 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424279 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184280 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574281 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374282 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154283 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574284 return results
4285
4286def _AndroidSpecificOnCommitChecks(input_api, output_api):
4287 """Groups commit checks that target android code."""
4288 results = []
4289 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224290 return results
4291
Chris Hall59f8d0c72020-05-01 07:31:194292# TODO(chrishall): could we additionally match on any path owned by
4293# ui/accessibility/OWNERS ?
4294_ACCESSIBILITY_PATHS = (
4295 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4296 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4297 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4298 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4299 r"^content[\\/]browser[\\/]accessibility[\\/]",
4300 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4301 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4302 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4303 r"^ui[\\/]accessibility[\\/]",
4304 r"^ui[\\/]views[\\/]accessibility[\\/]",
4305)
4306
4307def _CheckAccessibilityRelnotesField(input_api, output_api):
4308 """Checks that commits to accessibility code contain an AX-Relnotes field in
4309 their commit message."""
4310 def FileFilter(affected_file):
4311 paths = _ACCESSIBILITY_PATHS
4312 return input_api.FilterSourceFile(affected_file, white_list=paths)
4313
4314 # Only consider changes affecting accessibility paths.
4315 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4316 return []
4317
Akihiro Ota08108e542020-05-20 15:30:534318 # AX-Relnotes can appear in either the description or the footer.
4319 # When searching the description, require 'AX-Relnotes:' to appear at the
4320 # beginning of a line.
4321 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4322 description_has_relnotes = any(ax_regex.match(line)
4323 for line in input_api.change.DescriptionText().lower().splitlines())
4324
4325 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4326 'AX-Relnotes', [])
4327 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194328 return []
4329
4330 # TODO(chrishall): link to Relnotes documentation in message.
4331 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4332 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4333 "user-facing changes"
4334 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4335 "user-facing effects"
4336 "\n if this is confusing or annoying then please contact members "
4337 "of ui/accessibility/OWNERS.")
4338
4339 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224340
[email protected]22c9bd72011-03-27 16:47:394341def _CommonChecks(input_api, output_api):
4342 """Checks common to both upload and commit."""
4343 results = []
4344 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384345 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544346 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084347
4348 author = input_api.change.author_email
4349 if author and author not in _KNOWN_ROBOTS:
4350 results.extend(
4351 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4352
Chris Hall59f8d0c72020-05-01 07:31:194353 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194354 results.extend(
[email protected]760deea2013-12-10 19:33:494355 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234356 results.extend(
4357 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544358 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184359 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344360 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524361 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224362 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444363 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594364 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314365 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064366 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124367 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184368 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224369 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304370 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494371 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034372 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494373 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444374 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294375 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274376 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074377 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544378 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444379 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394380 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554381 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044382 results.extend(
4383 input_api.canned_checks.CheckChangeHasNoTabs(
4384 input_api,
4385 output_api,
4386 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404387 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164388 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084389 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244390 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474391 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044392 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054393 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144394 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234395 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434396 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404397 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154398 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034399 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134400 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264401 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504402 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364403 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064404 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134405 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434406 results.extend(input_api.RunTests(
4407 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264408 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124409 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024410 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514411 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364412 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004413 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514414 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244415
Vaclav Brozekcdc7defb2018-03-20 09:54:354416 for f in input_api.AffectedFiles():
4417 path, name = input_api.os_path.split(f.LocalPath())
4418 if name == 'PRESUBMIT.py':
4419 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004420 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4421 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074422 # The PRESUBMIT.py file (and the directory containing it) might
4423 # have been affected by being moved or removed, so only try to
4424 # run the tests if they still exist.
4425 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4426 input_api, output_api, full_path,
4427 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394428 return results
[email protected]1f7b4172010-01-28 01:17:344429
[email protected]b337cb5b2011-01-23 21:24:054430
[email protected]b8079ae4a2012-12-05 19:56:494431def _CheckPatchFiles(input_api, output_api):
4432 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4433 if f.LocalPath().endswith(('.orig', '.rej'))]
4434 if problems:
4435 return [output_api.PresubmitError(
4436 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034437 else:
4438 return []
[email protected]b8079ae4a2012-12-05 19:56:494439
4440
Kent Tamura5a8755d2017-06-29 23:37:074441def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214442 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4443 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4444 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074445 include_re = input_api.re.compile(
4446 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4447 extension_re = input_api.re.compile(r'\.[a-z]+$')
4448 errors = []
4449 for f in input_api.AffectedFiles():
4450 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4451 continue
4452 found_line_number = None
4453 found_macro = None
4454 for line_num, line in f.ChangedContents():
4455 match = macro_re.search(line)
4456 if match:
4457 found_line_number = line_num
4458 found_macro = match.group(2)
4459 break
4460 if not found_line_number:
4461 continue
4462
4463 found_include = False
4464 for line in f.NewContents():
4465 if include_re.search(line):
4466 found_include = True
4467 break
4468 if found_include:
4469 continue
4470
4471 if not f.LocalPath().endswith('.h'):
4472 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4473 try:
4474 content = input_api.ReadFile(primary_header_path, 'r')
4475 if include_re.search(content):
4476 continue
4477 except IOError:
4478 pass
4479 errors.append('%s:%d %s macro is used without including build/'
4480 'build_config.h.'
4481 % (f.LocalPath(), found_line_number, found_macro))
4482 if errors:
4483 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4484 return []
4485
4486
[email protected]b00342e7f2013-03-26 16:21:544487def _DidYouMeanOSMacro(bad_macro):
4488 try:
4489 return {'A': 'OS_ANDROID',
4490 'B': 'OS_BSD',
4491 'C': 'OS_CHROMEOS',
4492 'F': 'OS_FREEBSD',
4493 'L': 'OS_LINUX',
4494 'M': 'OS_MACOSX',
4495 'N': 'OS_NACL',
4496 'O': 'OS_OPENBSD',
4497 'P': 'OS_POSIX',
4498 'S': 'OS_SOLARIS',
4499 'W': 'OS_WIN'}[bad_macro[3].upper()]
4500 except KeyError:
4501 return ''
4502
4503
4504def _CheckForInvalidOSMacrosInFile(input_api, f):
4505 """Check for sensible looking, totally invalid OS macros."""
4506 preprocessor_statement = input_api.re.compile(r'^\s*#')
4507 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4508 results = []
4509 for lnum, line in f.ChangedContents():
4510 if preprocessor_statement.search(line):
4511 for match in os_macro.finditer(line):
4512 if not match.group(1) in _VALID_OS_MACROS:
4513 good = _DidYouMeanOSMacro(match.group(1))
4514 did_you_mean = ' (did you mean %s?)' % good if good else ''
4515 results.append(' %s:%d %s%s' % (f.LocalPath(),
4516 lnum,
4517 match.group(1),
4518 did_you_mean))
4519 return results
4520
4521
4522def _CheckForInvalidOSMacros(input_api, output_api):
4523 """Check all affected files for invalid OS macros."""
4524 bad_macros = []
tzik3f295992018-12-04 20:32:234525 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474526 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544527 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4528
4529 if not bad_macros:
4530 return []
4531
4532 return [output_api.PresubmitError(
4533 'Possibly invalid OS macro[s] found. Please fix your code\n'
4534 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4535
lliabraa35bab3932014-10-01 12:16:444536
4537def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4538 """Check all affected files for invalid "if defined" macros."""
4539 ALWAYS_DEFINED_MACROS = (
4540 "TARGET_CPU_PPC",
4541 "TARGET_CPU_PPC64",
4542 "TARGET_CPU_68K",
4543 "TARGET_CPU_X86",
4544 "TARGET_CPU_ARM",
4545 "TARGET_CPU_MIPS",
4546 "TARGET_CPU_SPARC",
4547 "TARGET_CPU_ALPHA",
4548 "TARGET_IPHONE_SIMULATOR",
4549 "TARGET_OS_EMBEDDED",
4550 "TARGET_OS_IPHONE",
4551 "TARGET_OS_MAC",
4552 "TARGET_OS_UNIX",
4553 "TARGET_OS_WIN32",
4554 )
4555 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4556 results = []
4557 for lnum, line in f.ChangedContents():
4558 for match in ifdef_macro.finditer(line):
4559 if match.group(1) in ALWAYS_DEFINED_MACROS:
4560 always_defined = ' %s is always defined. ' % match.group(1)
4561 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4562 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4563 lnum,
4564 always_defined,
4565 did_you_mean))
4566 return results
4567
4568
4569def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4570 """Check all affected files for invalid "if defined" macros."""
4571 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054572 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444573 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054574 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214575 continue
lliabraa35bab3932014-10-01 12:16:444576 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4577 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4578
4579 if not bad_macros:
4580 return []
4581
4582 return [output_api.PresubmitError(
4583 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4584 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4585 bad_macros)]
4586
4587
mlamouria82272622014-09-16 18:45:044588def _CheckForIPCRules(input_api, output_api):
4589 """Check for same IPC rules described in
4590 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4591 """
4592 base_pattern = r'IPC_ENUM_TRAITS\('
4593 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4594 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4595
4596 problems = []
4597 for f in input_api.AffectedSourceFiles(None):
4598 local_path = f.LocalPath()
4599 if not local_path.endswith('.h'):
4600 continue
4601 for line_number, line in f.ChangedContents():
4602 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4603 problems.append(
4604 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4605
4606 if problems:
4607 return [output_api.PresubmitPromptWarning(
4608 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4609 else:
4610 return []
4611
[email protected]b00342e7f2013-03-26 16:21:544612
Stephen Martinis97a394142018-06-07 23:06:054613def _CheckForLongPathnames(input_api, output_api):
4614 """Check to make sure no files being submitted have long paths.
4615 This causes issues on Windows.
4616 """
4617 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194618 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054619 local_path = f.LocalPath()
4620 # Windows has a path limit of 260 characters. Limit path length to 200 so
4621 # that we have some extra for the prefix on dev machines and the bots.
4622 if len(local_path) > 200:
4623 problems.append(local_path)
4624
4625 if problems:
4626 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4627 else:
4628 return []
4629
4630
Daniel Bratell8ba52722018-03-02 16:06:144631def _CheckForIncludeGuards(input_api, output_api):
4632 """Check that header files have proper guards against multiple inclusion.
4633 If a file should not have such guards (and it probably should) then it
4634 should include the string "no-include-guard-because-multiply-included".
4635 """
Daniel Bratell6a75baef62018-06-04 10:04:454636 def is_chromium_header_file(f):
4637 # We only check header files under the control of the Chromium
4638 # project. That is, those outside third_party apart from
4639 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324640 # We also exclude *_message_generator.h headers as they use
4641 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454642 file_with_path = input_api.os_path.normpath(f.LocalPath())
4643 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324644 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454645 (not file_with_path.startswith('third_party') or
4646 file_with_path.startswith(
4647 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144648
4649 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344650 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144651
4652 errors = []
4653
Daniel Bratell6a75baef62018-06-04 10:04:454654 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144655 guard_name = None
4656 guard_line_number = None
4657 seen_guard_end = False
4658
4659 file_with_path = input_api.os_path.normpath(f.LocalPath())
4660 base_file_name = input_api.os_path.splitext(
4661 input_api.os_path.basename(file_with_path))[0]
4662 upper_base_file_name = base_file_name.upper()
4663
4664 expected_guard = replace_special_with_underscore(
4665 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144666
4667 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574668 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4669 # are too many (1000+) files with slight deviations from the
4670 # coding style. The most important part is that the include guard
4671 # is there, and that it's unique, not the name so this check is
4672 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144673 #
4674 # As code becomes more uniform, this could be made stricter.
4675
4676 guard_name_pattern_list = [
4677 # Anything with the right suffix (maybe with an extra _).
4678 r'\w+_H__?',
4679
Daniel Bratell39b5b062018-05-16 18:09:574680 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144681 r'\w+_h',
4682
4683 # Anything including the uppercase name of the file.
4684 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4685 upper_base_file_name)) + r'\w*',
4686 ]
4687 guard_name_pattern = '|'.join(guard_name_pattern_list)
4688 guard_pattern = input_api.re.compile(
4689 r'#ifndef\s+(' + guard_name_pattern + ')')
4690
4691 for line_number, line in enumerate(f.NewContents()):
4692 if 'no-include-guard-because-multiply-included' in line:
4693 guard_name = 'DUMMY' # To not trigger check outside the loop.
4694 break
4695
4696 if guard_name is None:
4697 match = guard_pattern.match(line)
4698 if match:
4699 guard_name = match.group(1)
4700 guard_line_number = line_number
4701
Daniel Bratell39b5b062018-05-16 18:09:574702 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454703 # don't match the chromium style guide, but new files should
4704 # get it right.
4705 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574706 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144707 errors.append(output_api.PresubmitPromptWarning(
4708 'Header using the wrong include guard name %s' % guard_name,
4709 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574710 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144711 else:
4712 # The line after #ifndef should have a #define of the same name.
4713 if line_number == guard_line_number + 1:
4714 expected_line = '#define %s' % guard_name
4715 if line != expected_line:
4716 errors.append(output_api.PresubmitPromptWarning(
4717 'Missing "%s" for include guard' % expected_line,
4718 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4719 'Expected: %r\nGot: %r' % (expected_line, line)))
4720
4721 if not seen_guard_end and line == '#endif // %s' % guard_name:
4722 seen_guard_end = True
4723 elif seen_guard_end:
4724 if line.strip() != '':
4725 errors.append(output_api.PresubmitPromptWarning(
4726 'Include guard %s not covering the whole file' % (
4727 guard_name), [f.LocalPath()]))
4728 break # Nothing else to check and enough to warn once.
4729
4730 if guard_name is None:
4731 errors.append(output_api.PresubmitPromptWarning(
4732 'Missing include guard %s' % expected_guard,
4733 [f.LocalPath()],
4734 'Missing include guard in %s\n'
4735 'Recommended name: %s\n'
4736 'This check can be disabled by having the string\n'
4737 'no-include-guard-because-multiply-included in the header.' %
4738 (f.LocalPath(), expected_guard)))
4739
4740 return errors
4741
4742
mostynbb639aca52015-01-07 20:31:234743def _CheckForWindowsLineEndings(input_api, output_api):
4744 """Check source code and known ascii text files for Windows style line
4745 endings.
4746 """
earthdok1b5e0ee2015-03-10 15:19:104747 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234748
4749 file_inclusion_pattern = (
4750 known_text_files,
4751 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4752 )
4753
mostynbb639aca52015-01-07 20:31:234754 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534755 source_file_filter = lambda f: input_api.FilterSourceFile(
4756 f, white_list=file_inclusion_pattern, black_list=None)
4757 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504758 include_file = False
4759 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234760 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504761 include_file = True
4762 if include_file:
4763 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234764
4765 if problems:
4766 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4767 'these files to contain Windows style line endings?\n' +
4768 '\n'.join(problems))]
4769
4770 return []
4771
4772
Vaclav Brozekd5de76a2018-03-17 07:57:504773def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134774 """Checks that all source files use SYSLOG properly."""
4775 syslog_files = []
4776 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564777 for line_number, line in f.ChangedContents():
4778 if 'SYSLOG' in line:
4779 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4780
pastarmovj89f7ee12016-09-20 14:58:134781 if syslog_files:
4782 return [output_api.PresubmitPromptWarning(
4783 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4784 ' calls.\nFiles to check:\n', items=syslog_files)]
4785 return []
4786
4787
[email protected]1f7b4172010-01-28 01:17:344788def CheckChangeOnUpload(input_api, output_api):
4789 results = []
4790 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474791 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284792 results.extend(
jam93a6ee792017-02-08 23:59:224793 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194794 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224795 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134796 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164797 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534798 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194799 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274800 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544801 return results
[email protected]ca8d1982009-02-19 16:33:124802
4803
[email protected]1bfb8322014-04-23 01:02:414804def GetTryServerMasterForBot(bot):
4805 """Returns the Try Server master for the given bot.
4806
[email protected]0bb112362014-07-26 04:38:324807 It tries to guess the master from the bot name, but may still fail
4808 and return None. There is no longer a default master.
4809 """
4810 # Potentially ambiguous bot names are listed explicitly.
4811 master_map = {
tandriie5587792016-07-14 00:34:504812 'chromium_presubmit': 'master.tryserver.chromium.linux',
4813 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414814 }
[email protected]0bb112362014-07-26 04:38:324815 master = master_map.get(bot)
4816 if not master:
wnwen4fbaab82016-05-25 12:54:364817 if 'android' in bot:
tandriie5587792016-07-14 00:34:504818 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364819 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504820 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324821 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504822 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324823 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504824 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324825 return master
[email protected]1bfb8322014-04-23 01:02:414826
4827
[email protected]ca8d1982009-02-19 16:33:124828def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544829 results = []
[email protected]1f7b4172010-01-28 01:17:344830 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574831 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544832 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274833 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344834 input_api,
4835 output_api,
[email protected]2fdd1f362013-01-16 03:56:034836 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274837
jam93a6ee792017-02-08 23:59:224838 results.extend(
4839 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544840 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4841 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384842 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4843 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414844 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4845 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544846 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144847
4848
Rainhard Findlingfc31844c52020-05-15 09:58:264849def _CheckStrings(input_api, output_api):
4850 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024851 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4852 # footer is set to true.
4853 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264854 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024855 footer.lower()
4856 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264857 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024858
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144859 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264860 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144861 import sys
4862 from io import StringIO
4863
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144864 new_or_added_paths = set(f.LocalPath()
4865 for f in input_api.AffectedFiles()
4866 if (f.Action() == 'A' or f.Action() == 'M'))
4867 removed_paths = set(f.LocalPath()
4868 for f in input_api.AffectedFiles(include_deletes=True)
4869 if f.Action() == 'D')
4870
4871 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264872 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164873 if not affected_grds:
4874 return []
4875
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144876 affected_png_paths = [f.AbsoluteLocalPath()
4877 for f in input_api.AffectedFiles()
4878 if (f.LocalPath().endswith('.png'))]
4879
4880 # Check for screenshots. Developers can upload screenshots using
4881 # tools/translation/upload_screenshots.py which finds and uploads
4882 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4883 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4884 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4885 #
4886 # The logic here is as follows:
4887 #
4888 # - If the CL has a .png file under the screenshots directory for a grd
4889 # file, warn the developer. Actual images should never be checked into the
4890 # Chrome repo.
4891 #
4892 # - If the CL contains modified or new messages in grd files and doesn't
4893 # contain the corresponding .sha1 files, warn the developer to add images
4894 # and upload them via tools/translation/upload_screenshots.py.
4895 #
4896 # - If the CL contains modified or new messages in grd files and the
4897 # corresponding .sha1 files, everything looks good.
4898 #
4899 # - If the CL contains removed messages in grd files but the corresponding
4900 # .sha1 files aren't removed, warn the developer to remove them.
4901 unnecessary_screenshots = []
4902 missing_sha1 = []
4903 unnecessary_sha1_files = []
4904
Rainhard Findlingfc31844c52020-05-15 09:58:264905 # This checks verifies that the ICU syntax of messages this CL touched is
4906 # valid, and reports any found syntax errors.
4907 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4908 # without developers being aware of them. Later on, such ICU syntax errors
4909 # break message extraction for translation, hence would block Chromium
4910 # translations until they are fixed.
4911 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144912
4913 def _CheckScreenshotAdded(screenshots_dir, message_id):
4914 sha1_path = input_api.os_path.join(
4915 screenshots_dir, message_id + '.png.sha1')
4916 if sha1_path not in new_or_added_paths:
4917 missing_sha1.append(sha1_path)
4918
4919
4920 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4921 sha1_path = input_api.os_path.join(
4922 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034923 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144924 unnecessary_sha1_files.append(sha1_path)
4925
Rainhard Findlingfc31844c52020-05-15 09:58:264926
4927 def _ValidateIcuSyntax(text, level, signatures):
4928 """Validates ICU syntax of a text string.
4929
4930 Check if text looks similar to ICU and checks for ICU syntax correctness
4931 in this case. Reports various issues with ICU syntax and values of
4932 variants. Supports checking of nested messages. Accumulate information of
4933 each ICU messages found in the text for further checking.
4934
4935 Args:
4936 text: a string to check.
4937 level: a number of current nesting level.
4938 signatures: an accumulator, a list of tuple of (level, variable,
4939 kind, variants).
4940
4941 Returns:
4942 None if a string is not ICU or no issue detected.
4943 A tuple of (message, start index, end index) if an issue detected.
4944 """
4945 valid_types = {
4946 'plural': (frozenset(
4947 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4948 frozenset(['=1', 'other'])),
4949 'selectordinal': (frozenset(
4950 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4951 frozenset(['one', 'other'])),
4952 'select': (frozenset(), frozenset(['other'])),
4953 }
4954
4955 # Check if the message looks like an attempt to use ICU
4956 # plural. If yes - check if its syntax strictly matches ICU format.
4957 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4958 if not like:
4959 signatures.append((level, None, None, None))
4960 return
4961
4962 # Check for valid prefix and suffix
4963 m = re.match(
4964 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4965 r'(plural|selectordinal|select),\s*'
4966 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4967 if not m:
4968 return (('This message looks like an ICU plural, '
4969 'but does not follow ICU syntax.'), like.start(), like.end())
4970 starting, variable, kind, variant_pairs = m.groups()
4971 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4972 if depth:
4973 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4974 len(text))
4975 first = text[0]
4976 ending = text[last_pos:]
4977 if not starting:
4978 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4979 last_pos)
4980 if not ending or '}' not in ending:
4981 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4982 last_pos)
4983 elif first != '{':
4984 return (
4985 ('Invalid ICU format. Extra characters at the start of a complex '
4986 'message (go/icu-message-migration): "%s"') %
4987 starting, 0, len(starting))
4988 elif ending != '}':
4989 return (('Invalid ICU format. Extra characters at the end of a complex '
4990 'message (go/icu-message-migration): "%s"')
4991 % ending, last_pos - 1, len(text) - 1)
4992 if kind not in valid_types:
4993 return (('Unknown ICU message type %s. '
4994 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4995 known, required = valid_types[kind]
4996 defined_variants = set()
4997 for variant, variant_range, value, value_range in variants:
4998 start, end = variant_range
4999 if variant in defined_variants:
5000 return ('Variant "%s" is defined more than once' % variant,
5001 start, end)
5002 elif known and variant not in known:
5003 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5004 start, end)
5005 defined_variants.add(variant)
5006 # Check for nested structure
5007 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5008 if res:
5009 return (res[0], res[1] + value_range[0] + 1,
5010 res[2] + value_range[0] + 1)
5011 missing = required - defined_variants
5012 if missing:
5013 return ('Required variants missing: %s' % ', '.join(missing), 0,
5014 len(text))
5015 signatures.append((level, variable, kind, defined_variants))
5016
5017
5018 def _ParseIcuVariants(text, offset=0):
5019 """Parse variants part of ICU complex message.
5020
5021 Builds a tuple of variant names and values, as well as
5022 their offsets in the input string.
5023
5024 Args:
5025 text: a string to parse
5026 offset: additional offset to add to positions in the text to get correct
5027 position in the complete ICU string.
5028
5029 Returns:
5030 List of tuples, each tuple consist of four fields: variant name,
5031 variant name span (tuple of two integers), variant value, value
5032 span (tuple of two integers).
5033 """
5034 depth, start, end = 0, -1, -1
5035 variants = []
5036 key = None
5037 for idx, char in enumerate(text):
5038 if char == '{':
5039 if not depth:
5040 start = idx
5041 chunk = text[end + 1:start]
5042 key = chunk.strip()
5043 pos = offset + end + 1 + chunk.find(key)
5044 span = (pos, pos + len(key))
5045 depth += 1
5046 elif char == '}':
5047 if not depth:
5048 return variants, depth, offset + idx
5049 depth -= 1
5050 if not depth:
5051 end = idx
5052 variants.append((key, span, text[start:end + 1], (offset + start,
5053 offset + end + 1)))
5054 return variants, depth, offset + end + 1
5055
meacer8c0d3832019-12-26 21:46:165056 try:
5057 old_sys_path = sys.path
5058 sys.path = sys.path + [input_api.os_path.join(
5059 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5060 from helper import grd_helper
5061 finally:
5062 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145063
5064 for f in affected_grds:
5065 file_path = f.LocalPath()
5066 old_id_to_msg_map = {}
5067 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385068 # Note that this code doesn't check if the file has been deleted. This is
5069 # OK because it only uses the old and new file contents and doesn't load
5070 # the file via its path.
5071 # It's also possible that a file's content refers to a renamed or deleted
5072 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5073 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5074 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145075 if file_path.endswith('.grdp'):
5076 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585077 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395078 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585080 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395081 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145082 else:
meacerff8a9b62019-12-10 19:43:585083 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145084 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585085 old_id_to_msg_map = grd_helper.GetGrdMessages(
5086 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145087 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585088 new_id_to_msg_map = grd_helper.GetGrdMessages(
5089 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145090
5091 # Compute added, removed and modified message IDs.
5092 old_ids = set(old_id_to_msg_map)
5093 new_ids = set(new_id_to_msg_map)
5094 added_ids = new_ids - old_ids
5095 removed_ids = old_ids - new_ids
5096 modified_ids = set([])
5097 for key in old_ids.intersection(new_ids):
5098 if (old_id_to_msg_map[key].FormatXml()
5099 != new_id_to_msg_map[key].FormatXml()):
5100 modified_ids.add(key)
5101
5102 grd_name, ext = input_api.os_path.splitext(
5103 input_api.os_path.basename(file_path))
5104 screenshots_dir = input_api.os_path.join(
5105 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5106
Rainhard Findlingfc31844c52020-05-15 09:58:265107 if run_screenshot_check:
5108 # Check the screenshot directory for .png files. Warn if there is any.
5109 for png_path in affected_png_paths:
5110 if png_path.startswith(screenshots_dir):
5111 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145112
Rainhard Findlingfc31844c52020-05-15 09:58:265113 for added_id in added_ids:
5114 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145115
Rainhard Findlingfc31844c52020-05-15 09:58:265116 for modified_id in modified_ids:
5117 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
Rainhard Findlingfc31844c52020-05-15 09:58:265119 for removed_id in removed_ids:
5120 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5121
5122 # Check new and changed strings for ICU syntax errors.
5123 for key in added_ids.union(modified_ids):
5124 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5125 err = _ValidateIcuSyntax(msg, 0, [])
5126 if err is not None:
5127 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145128
5129 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265130 if run_screenshot_check:
5131 if unnecessary_screenshots:
5132 results.append(output_api.PresubmitNotifyResult(
5133 'Do not include actual screenshots in the changelist. Run '
5134 'tools/translate/upload_screenshots.py to upload them instead:',
5135 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136
Rainhard Findlingfc31844c52020-05-15 09:58:265137 if missing_sha1:
5138 results.append(output_api.PresubmitNotifyResult(
5139 'You are adding or modifying UI strings.\n'
5140 'To ensure the best translations, take screenshots of the relevant UI '
5141 '(https://g.co/chrome/translation) and add these files to your '
5142 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145143
Rainhard Findlingfc31844c52020-05-15 09:58:265144 if unnecessary_sha1_files:
5145 results.append(output_api.PresubmitNotifyResult(
5146 'You removed strings associated with these files. Remove:',
5147 sorted(unnecessary_sha1_files)))
5148 else:
5149 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5150 'screenshots check.'))
5151
5152 if icu_syntax_errors:
5153 results.append(output_api.PresubmitError(
5154 'ICU syntax errors were found in the following strings (problems or '
5155 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
5157 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125158
5159
5160def _CheckTranslationExpectations(input_api, output_api,
5161 repo_root=None,
5162 translation_expectations_path=None,
5163 grd_files=None):
5164 import sys
5165 affected_grds = [f for f in input_api.AffectedFiles()
5166 if (f.LocalPath().endswith('.grd') or
5167 f.LocalPath().endswith('.grdp'))]
5168 if not affected_grds:
5169 return []
5170
5171 try:
5172 old_sys_path = sys.path
5173 sys.path = sys.path + [
5174 input_api.os_path.join(
5175 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5176 from helper import git_helper
5177 from helper import translation_helper
5178 finally:
5179 sys.path = old_sys_path
5180
5181 # Check that translation expectations can be parsed and we can get a list of
5182 # translatable grd files. |repo_root| and |translation_expectations_path| are
5183 # only passed by tests.
5184 if not repo_root:
5185 repo_root = input_api.PresubmitLocalPath()
5186 if not translation_expectations_path:
5187 translation_expectations_path = input_api.os_path.join(
5188 repo_root, 'tools', 'gritsettings',
5189 'translation_expectations.pyl')
5190 if not grd_files:
5191 grd_files = git_helper.list_grds_in_repository(repo_root)
5192
5193 try:
5194 translation_helper.get_translatable_grds(repo_root, grd_files,
5195 translation_expectations_path)
5196 except Exception as e:
5197 return [output_api.PresubmitNotifyResult(
5198 'Failed to get a list of translatable grd files. This happens when:\n'
5199 ' - One of the modified grd or grdp files cannot be parsed or\n'
5200 ' - %s is not updated.\n'
5201 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5202 return []
Ken Rockotc31f4832020-05-29 18:58:515203
5204
5205def _CheckStableMojomChanges(input_api, output_api):
5206 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095207 changed_mojoms = input_api.AffectedFiles(
5208 include_deletes=True,
5209 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515210 delta = []
5211 for mojom in changed_mojoms:
5212 old_contents = ''.join(mojom.OldContents()) or None
5213 new_contents = ''.join(mojom.NewContents()) or None
5214 delta.append({
5215 'filename': mojom.LocalPath(),
5216 'old': '\n'.join(mojom.OldContents()) or None,
5217 'new': '\n'.join(mojom.NewContents()) or None,
5218 })
5219
5220 process = input_api.subprocess.Popen(
5221 [input_api.python_executable,
5222 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5223 'public', 'tools', 'mojom',
5224 'check_stable_mojom_compatibility.py'),
5225 '--src-root', input_api.PresubmitLocalPath()],
5226 stdin=input_api.subprocess.PIPE,
5227 stdout=input_api.subprocess.PIPE,
5228 stderr=input_api.subprocess.PIPE,
5229 universal_newlines=True)
5230 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5231 if process.returncode:
5232 return [output_api.PresubmitError(
5233 'One or more [Stable] mojom definitions appears to have been changed '
5234 'in a way that is not backward-compatible.',
5235 long_text=error)]
5236 return []