blob: 2c1166510e6ef127eecbcb19a255a304525e8c72 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4620 # sqlite is an imported third party dependency.
21 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5423 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5324 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1225 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0426 r".+[\\/]pnacl_shim\.c$",
27 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1429 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5431 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0432 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4033)
[email protected]ca8d1982009-02-19 16:33:1234
wnwenbdc444e2016-05-25 13:44:1535
[email protected]06e6d0ff2012-12-11 01:36:4436# Fragment of a regular expression that matches C++ and Objective-C++
37# implementation files.
38_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
39
wnwenbdc444e2016-05-25 13:44:1540
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1941# Fragment of a regular expression that matches C++ and Objective-C++
42# header files.
43_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
44
45
[email protected]06e6d0ff2012-12-11 01:36:4446# Regular expression that matches code only used for test binaries
47# (best effort).
48_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0449 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4450 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4451 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1252 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1853 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4454 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0455 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0556 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0457 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4758 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0459 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0860 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0461 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4162 # EarlGrey app side code for tests.
63 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1764 # Views Examples code
65 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4466)
[email protected]ca8d1982009-02-19 16:33:1267
Daniel Bratell609102be2019-03-27 20:53:2168_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1569
[email protected]eea609a2011-11-18 13:10:1270_TEST_ONLY_WARNING = (
71 'You might be calling functions intended only for testing from\n'
72 'production code. It is OK to ignore this warning if you know what\n'
73 'you are doing, as the heuristics used to detect the situation are\n'
Mohamed Heikal5cf63162019-10-25 19:59:0774 'not perfect. The commit queue will not block on this warning,\n'
75 'however the android-binary-size trybot will block if the method\n'
76 'exists in the release apk.')
[email protected]eea609a2011-11-18 13:10:1277
78
[email protected]cf9b78f2012-11-14 11:40:2879_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4080 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2181 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
82 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2883
Michael Thiessen44457642020-02-06 00:24:1584# Format: Sequence of tuples containing:
85# * Full import path.
86# * Sequence of strings to show when the pattern matches.
87# * Sequence of path or filename exceptions to this rule
88_BANNED_JAVA_IMPORTS = (
89 (
Colin Blundell170d78c82020-03-12 13:56:0490 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:1591 (
92 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
93 ),
94 (
95 'net/android/javatests/src/org/chromium/net/'
96 'AndroidProxySelectorTest.java',
97 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:0498 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:1599 ),
100 ),
101)
wnwenbdc444e2016-05-25 13:44:15102
Daniel Bratell609102be2019-03-27 20:53:21103# Format: Sequence of tuples containing:
104# * String pattern or, if starting with a slash, a regular expression.
105# * Sequence of strings to show when the pattern matches.
106# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41107_BANNED_JAVA_FUNCTIONS = (
108 (
109 'StrictMode.allowThreadDiskReads()',
110 (
111 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
112 'directly.',
113 ),
114 False,
115 ),
116 (
117 'StrictMode.allowThreadDiskWrites()',
118 (
119 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
120 'directly.',
121 ),
122 False,
123 ),
124)
125
Daniel Bratell609102be2019-03-27 20:53:21126# Format: Sequence of tuples containing:
127# * String pattern or, if starting with a slash, a regular expression.
128# * Sequence of strings to show when the pattern matches.
129# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59130_BANNED_OBJC_FUNCTIONS = (
131 (
132 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59135 'prohibited. Please use CrTrackingArea instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 False,
139 ),
140 (
[email protected]eaae1972014-04-16 04:17:26141 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59144 'instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 False,
148 ),
149 (
150 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertPoint:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertPoint:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
167 (
168 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20169 (
170 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59171 'Please use |convertRect:(point) fromView:nil| instead.',
172 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
173 ),
174 True,
175 ),
176 (
177 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20178 (
179 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59180 'Please use |convertRect:(point) toView:nil| instead.',
181 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
182 ),
183 True,
184 ),
185 (
186 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20187 (
188 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59189 'Please use |convertSize:(point) fromView:nil| instead.',
190 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
191 ),
192 True,
193 ),
194 (
195 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20196 (
197 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59198 'Please use |convertSize:(point) toView:nil| instead.',
199 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
200 ),
201 True,
202 ),
jif65398702016-10-27 10:19:48203 (
204 r"/\s+UTF8String\s*]",
205 (
206 'The use of -[NSString UTF8String] is dangerous as it can return null',
207 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
208 'Please use |SysNSStringToUTF8| instead.',
209 ),
210 True,
211 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34212 (
213 r'__unsafe_unretained',
214 (
215 'The use of __unsafe_unretained is almost certainly wrong, unless',
216 'when interacting with NSFastEnumeration or NSInvocation.',
217 'Please use __weak in files build with ARC, nothing otherwise.',
218 ),
219 False,
220 ),
Avi Drissman7382afa02019-04-29 23:27:13221 (
222 'freeWhenDone:NO',
223 (
224 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
225 'Foundation types is prohibited.',
226 ),
227 True,
228 ),
[email protected]127f18ec2012-06-16 05:05:59229)
230
Daniel Bratell609102be2019-03-27 20:53:21231# Format: Sequence of tuples containing:
232# * String pattern or, if starting with a slash, a regular expression.
233# * Sequence of strings to show when the pattern matches.
234# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54235_BANNED_IOS_OBJC_FUNCTIONS = (
236 (
237 r'/\bTEST[(]',
238 (
239 'TEST() macro should not be used in Objective-C++ code as it does not ',
240 'drain the autorelease pool at the end of the test. Use TEST_F() ',
241 'macro instead with a fixture inheriting from PlatformTest (or a ',
242 'typedef).'
243 ),
244 True,
245 ),
246 (
247 r'/\btesting::Test\b',
248 (
249 'testing::Test should not be used in Objective-C++ code as it does ',
250 'not drain the autorelease pool at the end of the test. Use ',
251 'PlatformTest instead.'
252 ),
253 True,
254 ),
255)
256
Peter K. Lee6c03ccff2019-07-15 14:40:05257# Format: Sequence of tuples containing:
258# * String pattern or, if starting with a slash, a regular expression.
259# * Sequence of strings to show when the pattern matches.
260# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
261_BANNED_IOS_EGTEST_FUNCTIONS = (
262 (
263 r'/\bEXPECT_OCMOCK_VERIFY\b',
264 (
265 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
266 'it is meant for GTests. Use [mock verify] instead.'
267 ),
268 True,
269 ),
270)
271
danakj7a2b7082019-05-21 21:13:51272# Directories that contain deprecated Bind() or Callback types.
273# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36274# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51275# echo "-- $i"
danakj710b4c02019-11-28 16:08:45276# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51277# done
278#
279# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
280# when they have been converted to modern callback types (OnceCallback,
281# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
282# checks for them and prevent regressions.
283_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51284 '^apps/',
danakj7a2b7082019-05-21 21:13:51285 '^base/callback.h', # Intentional.
danakj7a2b7082019-05-21 21:13:51286 '^chrome/browser/',
287 '^chrome/chrome_elf/',
danakj7a2b7082019-05-21 21:13:51288 '^chrome/installer/',
danakj7a2b7082019-05-21 21:13:51289 '^chrome/services/',
290 '^chrome/test/',
291 '^chrome/tools/',
292 '^chrome/utility/',
danakj7a2b7082019-05-21 21:13:51293 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51294 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51295 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51296 '^chromeos/network/',
danakj7a2b7082019-05-21 21:13:51297 '^chromeos/services/',
danakj7a2b7082019-05-21 21:13:51298 '^components/arc/',
299 '^components/assist_ranker/',
300 '^components/autofill/',
301 '^components/autofill_assistant/',
danakj7a2b7082019-05-21 21:13:51302 '^components/browser_watcher/',
danakj7a2b7082019-05-21 21:13:51303 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51304 '^components/chromeos_camera/',
305 '^components/component_updater/',
306 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51307 '^components/cronet/',
308 '^components/data_reduction_proxy/',
danakj7a2b7082019-05-21 21:13:51309 '^components/domain_reliability/',
danakjc8576092019-11-26 19:01:36310 '^components/dom_distiller/',
Joey Scarr164d7072020-04-21 03:13:39311 '^components/download/internal/common/',
danakj7a2b7082019-05-21 21:13:51312 '^components/drive/',
313 '^components/exo/',
danakj7a2b7082019-05-21 21:13:51314 '^components/feature_engagement/',
315 '^components/feedback/',
316 '^components/flags_ui/',
317 '^components/gcm_driver/',
danakj7a2b7082019-05-21 21:13:51318 '^components/guest_view/',
319 '^components/heap_profiling/',
320 '^components/history/',
321 '^components/image_fetcher/',
322 '^components/invalidation/',
323 '^components/keyed_service/',
324 '^components/login/',
325 '^components/metrics/',
326 '^components/metrics_services_manager/',
327 '^components/nacl/',
328 '^components/navigation_interception/',
329 '^components/net_log/',
330 '^components/network_time/',
331 '^components/ntp_snippets/',
332 '^components/ntp_tiles/',
danakj7a2b7082019-05-21 21:13:51333 '^components/offline_pages/',
334 '^components/omnibox/',
335 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51336 '^components/password_manager/',
337 '^components/payments/',
338 '^components/plugins/',
339 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51340 '^components/proxy_config/',
341 '^components/quirks/',
danakj7a2b7082019-05-21 21:13:51342 '^components/remote_cocoa/',
danakj7a2b7082019-05-21 21:13:51343 '^components/rlz/',
344 '^components/safe_browsing/',
345 '^components/search_engines/',
346 '^components/search_provider_logos/',
347 '^components/security_interstitials/',
348 '^components/security_state/',
349 '^components/services/',
350 '^components/sessions/',
351 '^components/signin/',
352 '^components/ssl_errors/',
353 '^components/storage_monitor/',
354 '^components/subresource_filter/',
355 '^components/suggestions/',
danakj7a2b7082019-05-21 21:13:51356 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51357 '^components/sync_preferences/',
358 '^components/sync_sessions/',
359 '^components/test/',
360 '^components/tracing/',
361 '^components/translate/',
362 '^components/ukm/',
363 '^components/update_client/',
364 '^components/upload_list/',
365 '^components/variations/',
366 '^components/visitedlink/',
danakj7a2b7082019-05-21 21:13:51367 '^components/webcrypto/',
368 '^components/webdata/',
369 '^components/webdata_services/',
danakj7a2b7082019-05-21 21:13:51370 '^device/bluetooth/',
Alan Cutter04a00642020-03-02 01:45:20371 '^extensions/browser/',
372 '^extensions/renderer/',
danakj7a2b7082019-05-21 21:13:51373 '^google_apis/dive/',
danakj7a2b7082019-05-21 21:13:51374 '^google_apis/gcm/',
danakj7a2b7082019-05-21 21:13:51375 '^ios/chrome/',
376 '^ios/components/',
377 '^ios/net/',
378 '^ios/web/',
379 '^ios/web_view/',
380 '^ipc/',
danakj7a2b7082019-05-21 21:13:51381 '^media/base/',
danakjc8576092019-11-26 19:01:36382 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51383 '^media/cast/',
384 '^media/cdm/',
385 '^media/device_monitors/',
danakj7a2b7082019-05-21 21:13:51386 '^media/filters/',
387 '^media/formats/',
388 '^media/gpu/',
389 '^media/mojo/',
danakj7a2b7082019-05-21 21:13:51390 '^media/renderers/',
danakj7a2b7082019-05-21 21:13:51391 '^net/',
392 '^ppapi/proxy/',
393 '^ppapi/shared_impl/',
394 '^ppapi/tests/',
395 '^ppapi/thunk/',
396 '^remoting/base/',
397 '^remoting/client/',
danakj7a2b7082019-05-21 21:13:51398 '^remoting/host/',
399 '^remoting/internal/',
danakj7a2b7082019-05-21 21:13:51400 '^remoting/protocol/',
danakj7a2b7082019-05-21 21:13:51401 '^services/',
danakj7a2b7082019-05-21 21:13:51402 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51403 '^tools/clang/base_bind_rewriters/', # Intentional.
404 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51405))
[email protected]127f18ec2012-06-16 05:05:59406
Daniel Bratell609102be2019-03-27 20:53:21407# Format: Sequence of tuples containing:
408# * String pattern or, if starting with a slash, a regular expression.
409# * Sequence of strings to show when the pattern matches.
410# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
411# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59412_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20413 (
Dave Tapuska98199b612019-07-10 13:30:44414 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53415 (
416 'New code should not use NULL. Use nullptr instead.',
417 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20418 False,
thomasandersone7caaa9b2017-03-29 19:22:53419 (),
420 ),
Peter Kasting94a56c42019-10-25 21:54:04421 (
422 r'/\busing namespace ',
423 (
424 'Using directives ("using namespace x") are banned by the Google Style',
425 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
426 'Explicitly qualify symbols or use using declarations ("using x::foo").',
427 ),
428 True,
429 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
430 ),
Antonio Gomes07300d02019-03-13 20:59:57431 # Make sure that gtest's FRIEND_TEST() macro is not used; the
432 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
433 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53434 (
[email protected]23e6cbc2012-06-16 18:51:20435 'FRIEND_TEST(',
436 (
[email protected]e3c945502012-06-26 20:01:49437 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20438 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
439 ),
440 False,
[email protected]7345da02012-11-27 14:31:49441 (),
[email protected]23e6cbc2012-06-16 18:51:20442 ),
443 (
Dave Tapuska98199b612019-07-10 13:30:44444 r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
thomasanderson4b569052016-09-14 20:15:53445 (
446 'Chrome clients wishing to select events on X windows should use',
447 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
448 'you are selecting events from the GPU process, or if you are using',
449 'an XDisplay other than gfx::GetXDisplay().',
450 ),
451 True,
452 (
Nick Diego Yamaneea6d999a2019-07-24 03:22:40453 r"^ui[\\/]events[\\/]x[\\/].*\.cc$",
Egor Paskoce145c42018-09-28 19:31:04454 r"^ui[\\/]gl[\\/].*\.cc$",
455 r"^media[\\/]gpu[\\/].*\.cc$",
456 r"^gpu[\\/].*\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:37457 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]xwmstartupcheck\.cc$",
458 ),
thomasanderson4b569052016-09-14 20:15:53459 ),
460 (
Dave Tapuska98199b612019-07-10 13:30:44461 r'/XInternAtom|xcb_intern_atom',
thomasandersone043e3ce2017-06-08 00:43:20462 (
thomasanderson11aa41d2017-06-08 22:22:38463 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20464 ),
465 True,
466 (
Egor Paskoce145c42018-09-28 19:31:04467 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
468 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
469 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20470 ),
471 ),
472 (
tomhudsone2c14d552016-05-26 17:07:46473 'setMatrixClip',
474 (
475 'Overriding setMatrixClip() is prohibited; ',
476 'the base function is deprecated. ',
477 ),
478 True,
479 (),
480 ),
481 (
[email protected]52657f62013-05-20 05:30:31482 'SkRefPtr',
483 (
484 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22485 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31486 ),
487 True,
488 (),
489 ),
490 (
491 'SkAutoRef',
492 (
493 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22494 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31495 ),
496 True,
497 (),
498 ),
499 (
500 'SkAutoTUnref',
501 (
502 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22503 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31504 ),
505 True,
506 (),
507 ),
508 (
509 'SkAutoUnref',
510 (
511 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
512 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22513 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31514 ),
515 True,
516 (),
517 ),
[email protected]d89eec82013-12-03 14:10:59518 (
519 r'/HANDLE_EINTR\(.*close',
520 (
521 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
522 'descriptor will be closed, and it is incorrect to retry the close.',
523 'Either call close directly and ignore its return value, or wrap close',
524 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
525 ),
526 True,
527 (),
528 ),
529 (
530 r'/IGNORE_EINTR\((?!.*close)',
531 (
532 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
533 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
534 ),
535 True,
536 (
537 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04538 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
539 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59540 ),
541 ),
[email protected]ec5b3f02014-04-04 18:43:43542 (
543 r'/v8::Extension\(',
544 (
545 'Do not introduce new v8::Extensions into the code base, use',
546 'gin::Wrappable instead. See http://crbug.com/334679',
547 ),
548 True,
[email protected]f55c90ee62014-04-12 00:50:03549 (
Egor Paskoce145c42018-09-28 19:31:04550 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03551 ),
[email protected]ec5b3f02014-04-04 18:43:43552 ),
skyostilf9469f72015-04-20 10:38:52553 (
jame2d1a952016-04-02 00:27:10554 '#pragma comment(lib,',
555 (
556 'Specify libraries to link with in build files and not in the source.',
557 ),
558 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41559 (
tzik3f295992018-12-04 20:32:23560 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04561 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41562 ),
jame2d1a952016-04-02 00:27:10563 ),
fdorayc4ac18d2017-05-01 21:39:59564 (
Gabriel Charette7cc6c432018-04-25 20:52:02565 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59566 (
567 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
568 ),
569 False,
570 (),
571 ),
572 (
Gabriel Charette7cc6c432018-04-25 20:52:02573 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59574 (
575 'Consider using THREAD_CHECKER macros instead of the class directly.',
576 ),
577 False,
578 (),
579 ),
dbeamb6f4fde2017-06-15 04:03:06580 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06581 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
582 (
583 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
584 'deprecated (http://crbug.com/634507). Please avoid converting away',
585 'from the Time types in Chromium code, especially if any math is',
586 'being done on time values. For interfacing with platform/library',
587 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
588 'type converter methods instead. For faking TimeXXX values (for unit',
589 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
590 'other use cases, please contact base/time/OWNERS.',
591 ),
592 False,
593 (),
594 ),
595 (
dbeamb6f4fde2017-06-15 04:03:06596 'CallJavascriptFunctionUnsafe',
597 (
598 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
599 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
600 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
601 ),
602 False,
603 (
Egor Paskoce145c42018-09-28 19:31:04604 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
605 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
606 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06607 ),
608 ),
dskiba1474c2bfd62017-07-20 02:19:24609 (
610 'leveldb::DB::Open',
611 (
612 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
613 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
614 "Chrome's tracing, making their memory usage visible.",
615 ),
616 True,
617 (
618 r'^third_party/leveldatabase/.*\.(cc|h)$',
619 ),
Gabriel Charette0592c3a2017-07-26 12:02:04620 ),
621 (
Chris Mumfordc38afb62017-10-09 17:55:08622 'leveldb::NewMemEnv',
623 (
624 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58625 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
626 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08627 ),
628 True,
629 (
630 r'^third_party/leveldatabase/.*\.(cc|h)$',
631 ),
632 ),
633 (
Gabriel Charetted9839bc2017-07-29 14:17:47634 'RunLoop::QuitCurrent',
635 (
Robert Liao64b7ab22017-08-04 23:03:43636 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
637 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47638 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41639 False,
Gabriel Charetted9839bc2017-07-29 14:17:47640 (),
Gabriel Charettea44975052017-08-21 23:14:04641 ),
642 (
643 'base::ScopedMockTimeMessageLoopTaskRunner',
644 (
Gabriel Charette87cc1af2018-04-25 20:52:51645 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11646 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51647 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
648 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
649 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04650 ),
Gabriel Charette87cc1af2018-04-25 20:52:51651 False,
Gabriel Charettea44975052017-08-21 23:14:04652 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57653 ),
654 (
Dave Tapuska98199b612019-07-10 13:30:44655 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57656 (
657 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02658 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57659 ),
660 True,
661 (),
Francois Doray43670e32017-09-27 12:40:38662 ),
663 (
Peter Kasting991618a62019-06-17 22:00:09664 r'/\bstd::stoi\b',
665 (
666 'std::stoi uses exceptions to communicate results. ',
667 'Use base::StringToInt() instead.',
668 ),
669 True,
670 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
671 ),
672 (
673 r'/\bstd::stol\b',
674 (
675 'std::stol uses exceptions to communicate results. ',
676 'Use base::StringToInt() instead.',
677 ),
678 True,
679 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
680 ),
681 (
682 r'/\bstd::stoul\b',
683 (
684 'std::stoul uses exceptions to communicate results. ',
685 'Use base::StringToUint() instead.',
686 ),
687 True,
688 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
689 ),
690 (
691 r'/\bstd::stoll\b',
692 (
693 'std::stoll uses exceptions to communicate results. ',
694 'Use base::StringToInt64() instead.',
695 ),
696 True,
697 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
698 ),
699 (
700 r'/\bstd::stoull\b',
701 (
702 'std::stoull uses exceptions to communicate results. ',
703 'Use base::StringToUint64() instead.',
704 ),
705 True,
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
708 (
709 r'/\bstd::stof\b',
710 (
711 'std::stof uses exceptions to communicate results. ',
712 'For locale-independent values, e.g. reading numbers from disk',
713 'profiles, use base::StringToDouble().',
714 'For user-visible values, parse using ICU.',
715 ),
716 True,
717 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
718 ),
719 (
720 r'/\bstd::stod\b',
721 (
722 'std::stod uses exceptions to communicate results. ',
723 'For locale-independent values, e.g. reading numbers from disk',
724 'profiles, use base::StringToDouble().',
725 'For user-visible values, parse using ICU.',
726 ),
727 True,
728 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
729 ),
730 (
731 r'/\bstd::stold\b',
732 (
733 'std::stold uses exceptions to communicate results. ',
734 'For locale-independent values, e.g. reading numbers from disk',
735 'profiles, use base::StringToDouble().',
736 'For user-visible values, parse using ICU.',
737 ),
738 True,
739 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
740 ),
741 (
Daniel Bratell69334cc2019-03-26 11:07:45742 r'/\bstd::to_string\b',
743 (
744 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09745 'For locale-independent strings, e.g. writing numbers to disk',
746 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45747 'For user-visible strings, use base::FormatNumber() and',
748 'the related functions in base/i18n/number_formatting.h.',
749 ),
Peter Kasting991618a62019-06-17 22:00:09750 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21751 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45752 ),
753 (
754 r'/\bstd::shared_ptr\b',
755 (
756 'std::shared_ptr should not be used. Use scoped_refptr instead.',
757 ),
758 True,
Andreas Haas63f58792019-11-07 10:56:44759 [_THIRD_PARTY_EXCEPT_BLINK,
760 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
761 'array_buffer_contents\.(cc|h)'],
Daniel Bratell609102be2019-03-27 20:53:21762 ),
763 (
Peter Kasting991618a62019-06-17 22:00:09764 r'/\bstd::weak_ptr\b',
765 (
766 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
767 ),
768 True,
769 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
770 ),
771 (
Daniel Bratell609102be2019-03-27 20:53:21772 r'/\blong long\b',
773 (
774 'long long is banned. Use stdint.h if you need a 64 bit number.',
775 ),
776 False, # Only a warning since it is already used.
777 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
778 ),
779 (
780 r'/\bstd::bind\b',
781 (
782 'std::bind is banned because of lifetime risks.',
783 'Use base::BindOnce or base::BindRepeating instead.',
784 ),
785 True,
786 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
787 ),
788 (
789 r'/\b#include <chrono>\b',
790 (
791 '<chrono> overlaps with Time APIs in base. Keep using',
792 'base classes.',
793 ),
794 True,
795 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
796 ),
797 (
798 r'/\b#include <exception>\b',
799 (
800 'Exceptions are banned and disabled in Chromium.',
801 ),
802 True,
803 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
804 ),
805 (
806 r'/\bstd::function\b',
807 (
808 'std::function is banned. Instead use base::Callback which directly',
809 'supports Chromium\'s weak pointers, ref counting and more.',
810 ),
Peter Kasting991618a62019-06-17 22:00:09811 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21812 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
813 ),
814 (
815 r'/\b#include <random>\b',
816 (
817 'Do not use any random number engines from <random>. Instead',
818 'use base::RandomBitGenerator.',
819 ),
820 True,
821 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
822 ),
823 (
824 r'/\bstd::ratio\b',
825 (
826 'std::ratio is banned by the Google Style Guide.',
827 ),
828 True,
829 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45830 ),
831 (
Francois Doray43670e32017-09-27 12:40:38832 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
833 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
834 (
835 'Use the new API in base/threading/thread_restrictions.h.',
836 ),
Gabriel Charette04b138f2018-08-06 00:03:22837 False,
Francois Doray43670e32017-09-27 12:40:38838 (),
839 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38840 (
danakj7a2b7082019-05-21 21:13:51841 r'/\bbase::Bind\(',
842 (
843 'Please use base::Bind{Once,Repeating} instead',
844 'of base::Bind. (crbug.com/714018)',
845 ),
846 False,
Erik Staaba737d7602019-11-25 18:41:07847 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51848 ),
849 (
850 r'/\bbase::Callback[<:]',
851 (
852 'Please use base::{Once,Repeating}Callback instead',
853 'of base::Callback. (crbug.com/714018)',
854 ),
855 False,
Erik Staaba737d7602019-11-25 18:41:07856 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51857 ),
858 (
859 r'/\bbase::Closure\b',
860 (
861 'Please use base::{Once,Repeating}Closure instead',
862 'of base::Closure. (crbug.com/714018)',
863 ),
864 False,
Erik Staaba737d7602019-11-25 18:41:07865 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51866 ),
867 (
Michael Giuffrida7f93d6922019-04-19 14:39:58868 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19869 (
870 'RunMessageLoop is deprecated, use RunLoop instead.',
871 ),
872 False,
873 (),
874 ),
875 (
Dave Tapuska98199b612019-07-10 13:30:44876 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19877 (
878 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
879 ),
880 False,
881 (),
882 ),
883 (
Dave Tapuska98199b612019-07-10 13:30:44884 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19885 (
886 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
887 "if you're convinced you need this.",
888 ),
889 False,
890 (),
891 ),
892 (
Dave Tapuska98199b612019-07-10 13:30:44893 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19894 (
895 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04896 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19897 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
898 'async events instead of flushing threads.',
899 ),
900 False,
901 (),
902 ),
903 (
904 r'MessageLoopRunner',
905 (
906 'MessageLoopRunner is deprecated, use RunLoop instead.',
907 ),
908 False,
909 (),
910 ),
911 (
Dave Tapuska98199b612019-07-10 13:30:44912 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19913 (
914 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
915 "gab@ if you found a use case where this is the only solution.",
916 ),
917 False,
918 (),
919 ),
920 (
Victor Costane48a2e82019-03-15 22:02:34921 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16922 (
Victor Costane48a2e82019-03-15 22:02:34923 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16924 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
925 ),
926 True,
927 (
928 r'^sql/initialization\.(cc|h)$',
929 r'^third_party/sqlite/.*\.(c|cc|h)$',
930 ),
931 ),
Matt Menke7f520a82018-03-28 21:38:37932 (
Dave Tapuska98199b612019-07-10 13:30:44933 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47934 (
935 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
936 'base::RandomShuffle instead.'
937 ),
938 True,
939 (),
940 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24941 (
942 'ios/web/public/test/http_server',
943 (
944 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
945 ),
946 False,
947 (),
948 ),
Robert Liao764c9492019-01-24 18:46:28949 (
950 'GetAddressOf',
951 (
952 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Robert Liaoe794041e2019-10-03 17:16:46953 'implicated in a few leaks. Use operator& instead. See ',
954 'http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28955 ),
956 True,
957 (),
958 ),
Antonio Gomes07300d02019-03-13 20:59:57959 (
960 'DEFINE_TYPE_CASTS',
961 (
962 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
963 '//third_party/blink/renderer/platform/casting.h.'
964 ),
965 True,
966 (
967 r'^third_party/blink/renderer/.*\.(cc|h)$',
968 ),
969 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38970 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45971 r'/\bIsHTML.+Element\(\b',
972 (
973 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
974 ' helpers IsA<HTMLXXXXElement> from ',
975 '//third_party/blink/renderer/platform/casting.h.'
976 ),
977 False,
978 (
979 r'^third_party/blink/renderer/.*\.(cc|h)$',
980 ),
981 ),
982 (
983 r'/\bToHTML.+Element(|OrNull)\(\b',
984 (
985 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
986 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
987 'and DynamicTo<HTMLXXXXElement> from ',
988 '//third_party/blink/renderer/platform/casting.h.'
989 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
990 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
991 ),
992 False,
993 (
994 r'^third_party/blink/renderer/.*\.(cc|h)$',
995 ),
996 ),
997 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37998 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38999 (
1000 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
1001 ),
1002 True,
1003 (),
1004 ),
Ben Lewisa9514602019-04-29 17:53:051005 (
1006 'SHFileOperation',
1007 (
1008 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1009 'complex functions to achieve the same goals. Use IFileOperation for ',
1010 'any esoteric actions instead.'
1011 ),
1012 True,
1013 (),
1014 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181015 (
Cliff Smolinsky81951642019-04-30 21:39:511016 'StringFromGUID2',
1017 (
1018 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
1019 'Use base::win::String16FromGUID instead.'
1020 ),
1021 True,
1022 (
1023 r'/base/win/win_util_unittest.cc'
1024 ),
1025 ),
1026 (
1027 'StringFromCLSID',
1028 (
1029 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
1030 'Use base::win::String16FromGUID instead.'
1031 ),
1032 True,
1033 (
1034 r'/base/win/win_util_unittest.cc'
1035 ),
1036 ),
1037 (
Avi Drissman7382afa02019-04-29 23:27:131038 'kCFAllocatorNull',
1039 (
1040 'The use of kCFAllocatorNull with the NoCopy creation of ',
1041 'CoreFoundation types is prohibited.',
1042 ),
1043 True,
1044 (),
1045 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291046 (
1047 'mojo::ConvertTo',
1048 (
1049 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1050 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1051 'StringTraits if you would like to convert between custom types and',
1052 'the wire format of mojom types.'
1053 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221054 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291055 (
Wezf89dec092019-09-11 19:38:331056 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1057 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291058 r'^third_party/blink/.*\.(cc|h)$',
1059 r'^content/renderer/.*\.(cc|h)$',
1060 ),
1061 ),
Robert Liao1d78df52019-11-11 20:02:011062 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161063 'GetInterfaceProvider',
1064 (
1065 'InterfaceProvider is deprecated.',
1066 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1067 'or Platform::GetBrowserInterfaceBroker.'
1068 ),
1069 False,
1070 (),
1071 ),
1072 (
Robert Liao1d78df52019-11-11 20:02:011073 'CComPtr',
1074 (
1075 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1076 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1077 'details.'
1078 ),
1079 False,
1080 (),
1081 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201082 (
1083 r'/\b(IFACE|STD)METHOD_?\(',
1084 (
1085 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1086 'Instead, always use IFACEMETHODIMP in the declaration.'
1087 ),
1088 False,
1089 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1090 ),
Allen Bauer53b43fb12020-03-12 17:21:471091 (
1092 'set_owned_by_client',
1093 (
1094 'set_owned_by_client is deprecated.',
1095 'views::View already owns the child views by default. This introduces ',
1096 'a competing ownership model which makes the code difficult to reason ',
1097 'about. See http://crbug.com/1044687 for more details.'
1098 ),
1099 False,
1100 (),
1101 ),
Eric Secklerbe6f48d2020-05-06 18:09:121102 (
1103 r'/\bTRACE_EVENT_ASYNC_',
1104 (
1105 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1106 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1107 ),
1108 False,
1109 (
1110 r'^base/trace_event/.*',
1111 r'^base/tracing/.*',
1112 ),
1113 ),
[email protected]127f18ec2012-06-16 05:05:591114)
1115
Mario Sanchez Prada2472cab2019-09-18 10:58:311116# Format: Sequence of tuples containing:
1117# * String pattern or, if starting with a slash, a regular expression.
1118# * Sequence of strings to show when the pattern matches.
1119_DEPRECATED_MOJO_TYPES = (
1120 (
1121 r'/\bmojo::AssociatedBinding\b',
1122 (
1123 'mojo::AssociatedBinding<Interface> is deprecated.',
1124 'Use mojo::AssociatedReceiver<Interface> instead.',
1125 ),
1126 ),
1127 (
1128 r'/\bmojo::AssociatedBindingSet\b',
1129 (
1130 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1131 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1132 ),
1133 ),
1134 (
1135 r'/\bmojo::AssociatedInterfacePtr\b',
1136 (
1137 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1138 'Use mojo::AssociatedRemote<Interface> instead.',
1139 ),
1140 ),
1141 (
1142 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1143 (
1144 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1145 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1146 ),
1147 ),
1148 (
1149 r'/\bmojo::AssociatedInterfaceRequest\b',
1150 (
1151 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1152 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1153 ),
1154 ),
1155 (
1156 r'/\bmojo::Binding\b',
1157 (
1158 'mojo::Binding<Interface> is deprecated.',
1159 'Use mojo::Receiver<Interface> instead.',
1160 ),
1161 ),
1162 (
1163 r'/\bmojo::BindingSet\b',
1164 (
1165 'mojo::BindingSet<Interface> is deprecated.',
1166 'Use mojo::ReceiverSet<Interface> instead.',
1167 ),
1168 ),
1169 (
1170 r'/\bmojo::InterfacePtr\b',
1171 (
1172 'mojo::InterfacePtr<Interface> is deprecated.',
1173 'Use mojo::Remote<Interface> instead.',
1174 ),
1175 ),
1176 (
1177 r'/\bmojo::InterfacePtrInfo\b',
1178 (
1179 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1180 'Use mojo::PendingRemote<Interface> instead.',
1181 ),
1182 ),
1183 (
1184 r'/\bmojo::InterfaceRequest\b',
1185 (
1186 'mojo::InterfaceRequest<Interface> is deprecated.',
1187 'Use mojo::PendingReceiver<Interface> instead.',
1188 ),
1189 ),
1190 (
1191 r'/\bmojo::MakeRequest\b',
1192 (
1193 'mojo::MakeRequest is deprecated.',
1194 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1195 ),
1196 ),
1197 (
1198 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1199 (
1200 'mojo::MakeRequest is deprecated.',
1201 'Use mojo::AssociatedRemote::'
1202 'BindNewEndpointAndPassDedicatedReceiverForTesting() instead.',
1203 ),
1204 ),
1205 (
1206 r'/\bmojo::MakeStrongBinding\b',
1207 (
1208 'mojo::MakeStrongBinding is deprecated.',
1209 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1210 'mojo::MakeSelfOwnedReceiver() instead.',
1211 ),
1212 ),
1213 (
1214 r'/\bmojo::MakeStrongAssociatedBinding\b',
1215 (
1216 'mojo::MakeStrongAssociatedBinding is deprecated.',
1217 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1218 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1219 ),
1220 ),
1221 (
1222 r'/\bmojo::StrongAssociatedBindingSet\b',
1223 (
1224 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1225 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1226 ),
1227 ),
1228 (
1229 r'/\bmojo::StrongBindingSet\b',
1230 (
1231 'mojo::StrongBindingSet<Interface> is deprecated.',
1232 'Use mojo::UniqueReceiverSet<Interface> instead.',
1233 ),
1234 ),
1235)
wnwenbdc444e2016-05-25 13:44:151236
mlamouria82272622014-09-16 18:45:041237_IPC_ENUM_TRAITS_DEPRECATED = (
1238 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501239 'See http://www.chromium.org/Home/chromium-security/education/'
1240 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041241
Stephen Martinis97a394142018-06-07 23:06:051242_LONG_PATH_ERROR = (
1243 'Some files included in this CL have file names that are too long (> 200'
1244 ' characters). If committed, these files will cause issues on Windows. See'
1245 ' https://crbug.com/612667 for more details.'
1246)
1247
Shenghua Zhangbfaa38b82017-11-16 21:58:021248_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041249 r".*[\\/]BuildHooksAndroidImpl\.java",
1250 r".*[\\/]LicenseContentProvider\.java",
1251 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281252 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021253]
[email protected]127f18ec2012-06-16 05:05:591254
Mohamed Heikald048240a2019-11-12 16:57:371255# List of image extensions that are used as resources in chromium.
1256_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1257
Sean Kau46e29bc2017-08-28 16:31:161258# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401259_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041260 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401261 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041262 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1263 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041264 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431265 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161266]
1267
1268
[email protected]b00342e7f2013-03-26 16:21:541269_VALID_OS_MACROS = (
1270 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081271 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541272 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:121273 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541274 'OS_BSD',
1275 'OS_CAT', # For testing.
1276 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041277 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541278 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371279 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541280 'OS_IOS',
1281 'OS_LINUX',
1282 'OS_MACOSX',
1283 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211284 'OS_NACL_NONSFI',
1285 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121286 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_OPENBSD',
1288 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371289 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541290 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_WIN',
1292)
1293
1294
Andrew Grieveb773bad2020-06-05 18:00:381295# These are not checked on the public chromium-presubmit trybot.
1296# Add files here that rely on .py files that exists only for target_os="android"
1297# checkouts (e.g. //third_party/catapult).
agrievef32bcc72016-04-04 14:57:401298_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:391299 'android_webview/tools/run_cts.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381300 'build/android/devil_chromium.pydeps',
1301 'build/android/gyp/create_bundle_wrapper_script.pydeps',
1302 'build/android/gyp/jinja_template.pydeps',
1303 'build/android/resource_sizes.pydeps',
1304 'build/android/test_runner.pydeps',
1305 'build/android/test_wrapper/logdog_wrapper.pydeps',
1306 'chrome/android/features/create_stripped_java_factory.pydeps',
1307 'testing/scripts/run_android_wpt.pydeps',
1308 'third_party/android_platform/development/scripts/stack.pydeps',
1309]
1310
1311
1312_GENERIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'base/android/jni_generator/jni_generator.pydeps',
1314 'base/android/jni_generator/jni_registration_generator.pydeps',
1315 'build/android/gyp/aar.pydeps',
1316 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271317 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361318 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381319 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111321 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/create_app_bundle_apks.pydeps',
1326 'build/android/gyp/create_app_bundle.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221328 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001329 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:591331 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421333 'build/android/gyp/dex_jdk_libs.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361335 'build/android/gyp/filter_zip.pydeps',
1336 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361337 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581339 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261341 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011342 'build/android/gyp/jetify_jar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361343 'build/android/gyp/lint.pydeps',
1344 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361345 'build/android/gyp/merge_manifest.pydeps',
1346 'build/android/gyp/prepare_resources.pydeps',
1347 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461348 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241349 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361350 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461351 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561352 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/incremental_install/generate_android_manifest.pydeps',
1354 'build/android/incremental_install/write_installer_json.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361355 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271356 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1357 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001358 'components/cronet/tools/generate_javadoc.pydeps',
1359 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381360 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001361 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381362 '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 = []
Hans Wennborg944479f2020-06-25 21:39:251618 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521619 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 """
Peng Huang9c5949a02020-06-11 19:20:541826 result = []
1827
1828 if line.endswith(" nocheck"):
1829 return result
1830
Mario Sanchez Prada2472cab2019-09-18 10:58:311831 matched = False
1832 if type_name[0:1] == '/':
1833 regex = type_name[1:]
1834 if input_api.re.search(regex, line):
1835 matched = True
1836 elif type_name in line:
1837 matched = True
1838
Mario Sanchez Prada2472cab2019-09-18 10:58:311839 if matched:
1840 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1841 for message_line in message:
1842 result.append(' %s' % message_line)
1843
1844 return result
1845
1846
[email protected]127f18ec2012-06-16 05:05:591847def _CheckNoBannedFunctions(input_api, output_api):
1848 """Make sure that banned functions are not used."""
1849 warnings = []
1850 errors = []
1851
wnwenbdc444e2016-05-25 13:44:151852 def IsBlacklisted(affected_file, blacklist):
1853 local_path = affected_file.LocalPath()
1854 for item in blacklist:
1855 if input_api.re.match(item, local_path):
1856 return True
1857 return False
1858
Peter K. Lee6c03ccff2019-07-15 14:40:051859 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541860 local_path = affected_file.LocalPath()
1861 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1862 return False
1863 basename = input_api.os_path.basename(local_path)
1864 if 'ios' in basename.split('_'):
1865 return True
1866 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1867 if sep and 'ios' in local_path.split(sep):
1868 return True
1869 return False
1870
wnwenbdc444e2016-05-25 13:44:151871 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311872 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1873 func_name, message)
1874 if problems:
wnwenbdc444e2016-05-25 13:44:151875 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311876 errors.extend(problems)
1877 else:
1878 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151879
Eric Stevensona9a980972017-09-23 00:04:411880 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1881 for f in input_api.AffectedFiles(file_filter=file_filter):
1882 for line_num, line in f.ChangedContents():
1883 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1884 CheckForMatch(f, line_num, line, func_name, message, error)
1885
[email protected]127f18ec2012-06-16 05:05:591886 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1887 for f in input_api.AffectedFiles(file_filter=file_filter):
1888 for line_num, line in f.ChangedContents():
1889 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151890 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591891
Peter K. Lee6c03ccff2019-07-15 14:40:051892 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541893 for line_num, line in f.ChangedContents():
1894 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1895 CheckForMatch(f, line_num, line, func_name, message, error)
1896
Peter K. Lee6c03ccff2019-07-15 14:40:051897 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1898 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1899 for line_num, line in f.ChangedContents():
1900 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1901 CheckForMatch(f, line_num, line, func_name, message, error)
1902
[email protected]127f18ec2012-06-16 05:05:591903 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1904 for f in input_api.AffectedFiles(file_filter=file_filter):
1905 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491906 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491907 if IsBlacklisted(f, excluded_paths):
1908 continue
wnwenbdc444e2016-05-25 13:44:151909 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591910
1911 result = []
1912 if (warnings):
1913 result.append(output_api.PresubmitPromptWarning(
1914 'Banned functions were used.\n' + '\n'.join(warnings)))
1915 if (errors):
1916 result.append(output_api.PresubmitError(
1917 'Banned functions were used.\n' + '\n'.join(errors)))
1918 return result
1919
1920
Michael Thiessen44457642020-02-06 00:24:151921def _CheckAndroidNoBannedImports(input_api, output_api):
1922 """Make sure that banned java imports are not used."""
1923 errors = []
1924
1925 def IsException(path, exceptions):
1926 for exception in exceptions:
1927 if (path.startswith(exception)):
1928 return True
1929 return False
1930
1931 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1932 for f in input_api.AffectedFiles(file_filter=file_filter):
1933 for line_num, line in f.ChangedContents():
1934 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1935 if IsException(f.LocalPath(), exceptions):
1936 continue;
1937 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1938 'import ' + import_name, message)
1939 if problems:
1940 errors.extend(problems)
1941 result = []
1942 if (errors):
1943 result.append(output_api.PresubmitError(
1944 'Banned imports were used.\n' + '\n'.join(errors)))
1945 return result
1946
1947
Mario Sanchez Prada2472cab2019-09-18 10:58:311948def _CheckNoDeprecatedMojoTypes(input_api, output_api):
1949 """Make sure that old Mojo types are not used."""
1950 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571951 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311952
Mario Sanchez Pradaaab91382019-12-19 08:57:091953 # For any path that is not an "ok" or an "error" path, a warning will be
1954 # raised if deprecated mojo types are found.
1955 ok_paths = ['components/arc']
1956 error_paths = ['third_party/blink', 'content']
1957
Mario Sanchez Prada2472cab2019-09-18 10:58:311958 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1959 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571960 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091961 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311962 continue
1963
1964 for line_num, line in f.ChangedContents():
1965 for func_name, message in _DEPRECATED_MOJO_TYPES:
1966 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1967 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571968
Mario Sanchez Prada2472cab2019-09-18 10:58:311969 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091970 # Raise errors inside |error_paths| and warnings everywhere else.
1971 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571972 errors.extend(problems)
1973 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311974 warnings.extend(problems)
1975
1976 result = []
1977 if (warnings):
1978 result.append(output_api.PresubmitPromptWarning(
1979 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571980 if (errors):
1981 result.append(output_api.PresubmitError(
1982 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311983 return result
1984
1985
[email protected]6c063c62012-07-11 19:11:061986def _CheckNoPragmaOnce(input_api, output_api):
1987 """Make sure that banned functions are not used."""
1988 files = []
1989 pattern = input_api.re.compile(r'^#pragma\s+once',
1990 input_api.re.MULTILINE)
1991 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1992 if not f.LocalPath().endswith('.h'):
1993 continue
1994 contents = input_api.ReadFile(f)
1995 if pattern.search(contents):
1996 files.append(f)
1997
1998 if files:
1999 return [output_api.PresubmitError(
2000 'Do not use #pragma once in header files.\n'
2001 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2002 files)]
2003 return []
2004
[email protected]127f18ec2012-06-16 05:05:592005
[email protected]e7479052012-09-19 00:26:122006def _CheckNoTrinaryTrueFalse(input_api, output_api):
2007 """Checks to make sure we don't introduce use of foo ? true : false."""
2008 problems = []
2009 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2010 for f in input_api.AffectedFiles():
2011 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2012 continue
2013
2014 for line_num, line in f.ChangedContents():
2015 if pattern.match(line):
2016 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2017
2018 if not problems:
2019 return []
2020 return [output_api.PresubmitPromptWarning(
2021 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2022 '\n'.join(problems))]
2023
2024
[email protected]55f9f382012-07-31 11:02:182025def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282026 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182027 change. Breaking - rules is an error, breaking ! rules is a
2028 warning.
2029 """
mohan.reddyf21db962014-10-16 12:26:472030 import sys
[email protected]55f9f382012-07-31 11:02:182031 # We need to wait until we have an input_api object and use this
2032 # roundabout construct to import checkdeps because this file is
2033 # eval-ed and thus doesn't have __file__.
2034 original_sys_path = sys.path
2035 try:
2036 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472037 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182038 import checkdeps
[email protected]55f9f382012-07-31 11:02:182039 from rules import Rule
2040 finally:
2041 # Restore sys.path to what it was before.
2042 sys.path = original_sys_path
2043
2044 added_includes = []
rhalavati08acd232017-04-03 07:23:282045 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242046 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182047 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062048 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502049 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082050 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062051 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502052 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082053 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062054 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502055 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082056 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182057
[email protected]26385172013-05-09 23:11:352058 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182059
2060 error_descriptions = []
2061 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282062 error_subjects = set()
2063 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:182064 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2065 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082066 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182067 description_with_path = '%s\n %s' % (path, rule_description)
2068 if rule_type == Rule.DISALLOW:
2069 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282070 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182071 else:
2072 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282073 warning_subjects.add("#includes")
2074
2075 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2076 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082077 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282078 description_with_path = '%s\n %s' % (path, rule_description)
2079 if rule_type == Rule.DISALLOW:
2080 error_descriptions.append(description_with_path)
2081 error_subjects.add("imports")
2082 else:
2083 warning_descriptions.append(description_with_path)
2084 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182085
Jinsuk Kim5a092672017-10-24 22:42:242086 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022087 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082088 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242089 description_with_path = '%s\n %s' % (path, rule_description)
2090 if rule_type == Rule.DISALLOW:
2091 error_descriptions.append(description_with_path)
2092 error_subjects.add("imports")
2093 else:
2094 warning_descriptions.append(description_with_path)
2095 warning_subjects.add("imports")
2096
[email protected]55f9f382012-07-31 11:02:182097 results = []
2098 if error_descriptions:
2099 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282100 'You added one or more %s that violate checkdeps rules.'
2101 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182102 error_descriptions))
2103 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422104 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282105 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182106 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282107 '%s? See relevant DEPS file(s) for details and contacts.' %
2108 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182109 warning_descriptions))
2110 return results
2111
2112
[email protected]fbcafe5a2012-08-08 15:31:222113def _CheckFilePermissions(input_api, output_api):
2114 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152115 if input_api.platform == 'win32':
2116 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292117 checkperms_tool = input_api.os_path.join(
2118 input_api.PresubmitLocalPath(),
2119 'tools', 'checkperms', 'checkperms.py')
2120 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472121 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392122 with input_api.CreateTemporaryFile() as file_list:
2123 for f in input_api.AffectedFiles():
2124 # checkperms.py file/directory arguments must be relative to the
2125 # repository.
2126 file_list.write(f.LocalPath() + '\n')
2127 file_list.close()
2128 args += ['--file-list', file_list.name]
2129 try:
2130 input_api.subprocess.check_output(args)
2131 return []
2132 except input_api.subprocess.CalledProcessError as error:
2133 return [output_api.PresubmitError(
2134 'checkperms.py failed:',
2135 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222136
2137
robertocn832f5992017-01-04 19:01:302138def _CheckTeamTags(input_api, output_api):
2139 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
2140 checkteamtags_tool = input_api.os_path.join(
2141 input_api.PresubmitLocalPath(),
2142 'tools', 'checkteamtags', 'checkteamtags.py')
2143 args = [input_api.python_executable, checkteamtags_tool,
2144 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:222145 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:302146 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
2147 'OWNERS']
2148 try:
2149 if files:
Roberto Carrillo8465e7a2019-07-17 18:39:052150 warnings = input_api.subprocess.check_output(args + files).splitlines()
2151 if warnings:
2152 return [output_api.PresubmitPromptWarning(warnings[0], warnings[1:])]
robertocn832f5992017-01-04 19:01:302153 return []
2154 except input_api.subprocess.CalledProcessError as error:
2155 return [output_api.PresubmitError(
2156 'checkteamtags.py failed:',
2157 long_text=error.output)]
2158
2159
[email protected]c8278b32012-10-30 20:35:492160def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
2161 """Makes sure we don't include ui/aura/window_property.h
2162 in header files.
2163 """
2164 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2165 errors = []
2166 for f in input_api.AffectedFiles():
2167 if not f.LocalPath().endswith('.h'):
2168 continue
2169 for line_num, line in f.ChangedContents():
2170 if pattern.match(line):
2171 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2172
2173 results = []
2174 if errors:
2175 results.append(output_api.PresubmitError(
2176 'Header files should not include ui/aura/window_property.h', errors))
2177 return results
2178
2179
[email protected]70ca77752012-11-20 03:45:032180def _CheckForVersionControlConflictsInFile(input_api, f):
2181 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2182 errors = []
2183 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162184 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232185 # First-level headers in markdown look a lot like version control
2186 # conflict markers. http://daringfireball.net/projects/markdown/basics
2187 continue
[email protected]70ca77752012-11-20 03:45:032188 if pattern.match(line):
2189 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2190 return errors
2191
2192
2193def _CheckForVersionControlConflicts(input_api, output_api):
2194 """Usually this is not intentional and will cause a compile failure."""
2195 errors = []
2196 for f in input_api.AffectedFiles():
2197 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2198
2199 results = []
2200 if errors:
2201 results.append(output_api.PresubmitError(
2202 'Version control conflict markers found, please resolve.', errors))
2203 return results
2204
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202205
estadee17314a02017-01-12 16:22:162206def _CheckGoogleSupportAnswerUrl(input_api, output_api):
2207 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2208 errors = []
2209 for f in input_api.AffectedFiles():
2210 for line_num, line in f.ChangedContents():
2211 if pattern.search(line):
2212 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2213
2214 results = []
2215 if errors:
2216 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502217 'Found Google support URL addressed by answer number. Please replace '
2218 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162219 return results
2220
[email protected]70ca77752012-11-20 03:45:032221
[email protected]06e6d0ff2012-12-11 01:36:442222def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
2223 def FilterFile(affected_file):
2224 """Filter function for use with input_api.AffectedSourceFiles,
2225 below. This filters out everything except non-test files from
2226 top-level directories that generally speaking should not hard-code
2227 service URLs (e.g. src/android_webview/, src/content/ and others).
2228 """
2229 return input_api.FilterSourceFile(
2230 affected_file,
Egor Paskoce145c42018-09-28 19:31:042231 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:442232 black_list=(_EXCLUDED_PATHS +
2233 _TEST_CODE_EXCLUDED_PATHS +
2234 input_api.DEFAULT_BLACK_LIST))
2235
reillyi38965732015-11-16 18:27:332236 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2237 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462238 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2239 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442240 problems = [] # items are (filename, line_number, line)
2241 for f in input_api.AffectedSourceFiles(FilterFile):
2242 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462243 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442244 problems.append((f.LocalPath(), line_num, line))
2245
2246 if problems:
[email protected]f7051d52013-04-02 18:31:422247 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442248 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582249 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442250 [' %s:%d: %s' % (
2251 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032252 else:
2253 return []
[email protected]06e6d0ff2012-12-11 01:36:442254
2255
James Cook6b6597c2019-11-06 22:05:292256def _CheckChromeOsSyncedPrefRegistration(input_api, output_api):
2257 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2258 def FileFilter(affected_file):
2259 """Includes directories known to be Chrome OS only."""
2260 return input_api.FilterSourceFile(
2261 affected_file,
2262 white_list=('^ash/',
2263 '^chromeos/', # Top-level src/chromeos.
2264 '/chromeos/', # Any path component.
2265 '^components/arc',
2266 '^components/exo'),
2267 black_list=(input_api.DEFAULT_BLACK_LIST))
2268
2269 prefs = []
2270 priority_prefs = []
2271 for f in input_api.AffectedFiles(file_filter=FileFilter):
2272 for line_num, line in f.ChangedContents():
2273 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2274 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2275 prefs.append(' %s' % line)
2276 if input_api.re.search(
2277 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2278 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2279 priority_prefs.append(' %s' % line)
2280
2281 results = []
2282 if (prefs):
2283 results.append(output_api.PresubmitPromptWarning(
2284 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2285 'by browser sync settings. If these prefs should be controlled by OS '
2286 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2287 if (priority_prefs):
2288 results.append(output_api.PresubmitPromptWarning(
2289 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2290 'controlled by browser sync settings. If these prefs should be '
2291 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2292 'instead.\n' + '\n'.join(prefs)))
2293 return results
2294
2295
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492296# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:272297def _CheckNoAbbreviationInPngFileName(input_api, output_api):
2298 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312299 The native_client_sdk directory is excluded because it has auto-generated PNG
2300 files for documentation.
[email protected]d2530012013-01-25 16:39:272301 """
[email protected]d2530012013-01-25 16:39:272302 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492303 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:042304 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312305 file_filter = lambda f: input_api.FilterSourceFile(
2306 f, white_list=white_list, black_list=black_list)
2307 for f in input_api.AffectedFiles(include_deletes=False,
2308 file_filter=file_filter):
2309 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272310
2311 results = []
2312 if errors:
2313 results.append(output_api.PresubmitError(
2314 'The name of PNG files should not have abbreviations. \n'
2315 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2316 'Contact [email protected] if you have questions.', errors))
2317 return results
2318
2319
Daniel Cheng4dcdb6b2017-04-13 08:30:172320def _ExtractAddRulesFromParsedDeps(parsed_deps):
2321 """Extract the rules that add dependencies from a parsed DEPS file.
2322
2323 Args:
2324 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2325 add_rules = set()
2326 add_rules.update([
2327 rule[1:] for rule in parsed_deps.get('include_rules', [])
2328 if rule.startswith('+') or rule.startswith('!')
2329 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502330 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172331 {}).iteritems():
2332 add_rules.update([
2333 rule[1:] for rule in rules
2334 if rule.startswith('+') or rule.startswith('!')
2335 ])
2336 return add_rules
2337
2338
2339def _ParseDeps(contents):
2340 """Simple helper for parsing DEPS files."""
2341 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172342 class _VarImpl:
2343
2344 def __init__(self, local_scope):
2345 self._local_scope = local_scope
2346
2347 def Lookup(self, var_name):
2348 """Implements the Var syntax."""
2349 try:
2350 return self._local_scope['vars'][var_name]
2351 except KeyError:
2352 raise Exception('Var is not defined: %s' % var_name)
2353
2354 local_scope = {}
2355 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172356 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592357 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172358 }
2359 exec contents in global_scope, local_scope
2360 return local_scope
2361
2362
2363def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:082364 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412365 a set of DEPS entries that we should look up.
2366
2367 For a directory (rather than a specific filename) we fake a path to
2368 a specific filename by adding /DEPS. This is chosen as a file that
2369 will seldom or never be subject to per-file include_rules.
2370 """
[email protected]2b438d62013-11-14 17:54:142371 # We ignore deps entries on auto-generated directories.
2372 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082373
Daniel Cheng4dcdb6b2017-04-13 08:30:172374 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2375 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2376
2377 added_deps = new_deps.difference(old_deps)
2378
[email protected]2b438d62013-11-14 17:54:142379 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172380 for added_dep in added_deps:
2381 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2382 continue
2383 # Assume that a rule that ends in .h is a rule for a specific file.
2384 if added_dep.endswith('.h'):
2385 results.add(added_dep)
2386 else:
2387 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082388 return results
2389
2390
[email protected]e871964c2013-05-13 14:14:552391def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
2392 """When a dependency prefixed with + is added to a DEPS file, we
2393 want to make sure that the change is reviewed by an OWNER of the
2394 target file or directory, to avoid layering violations from being
2395 introduced. This check verifies that this happens.
2396 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172397 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242398
2399 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492400 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242401 for f in input_api.AffectedFiles(include_deletes=False,
2402 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552403 filename = input_api.os_path.basename(f.LocalPath())
2404 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172405 virtual_depended_on_files.update(_CalculateAddedDeps(
2406 input_api.os_path,
2407 '\n'.join(f.OldContents()),
2408 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552409
[email protected]e871964c2013-05-13 14:14:552410 if not virtual_depended_on_files:
2411 return []
2412
2413 if input_api.is_committing:
2414 if input_api.tbr:
2415 return [output_api.PresubmitNotifyResult(
2416 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272417 if input_api.dry_run:
2418 return [output_api.PresubmitNotifyResult(
2419 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552420 if not input_api.change.issue:
2421 return [output_api.PresubmitError(
2422 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402423 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552424 output = output_api.PresubmitError
2425 else:
2426 output = output_api.PresubmitNotifyResult
2427
2428 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502429 owner_email, reviewers = (
2430 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2431 input_api,
2432 owners_db.email_regexp,
2433 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552434
2435 owner_email = owner_email or input_api.change.author_email
2436
[email protected]de4f7d22013-05-23 14:27:462437 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512438 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462439 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552440 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2441 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412442
2443 # We strip the /DEPS part that was added by
2444 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2445 # directory.
2446 def StripDeps(path):
2447 start_deps = path.rfind('/DEPS')
2448 if start_deps != -1:
2449 return path[:start_deps]
2450 else:
2451 return path
2452 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552453 for path in missing_files]
2454
2455 if unapproved_dependencies:
2456 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152457 output('You need LGTM from owners of depends-on paths in DEPS that were '
2458 'modified in this CL:\n %s' %
2459 '\n '.join(sorted(unapproved_dependencies)))]
2460 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2461 output_list.append(output(
2462 'Suggested missing target path OWNERS:\n %s' %
2463 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552464 return output_list
2465
2466 return []
2467
2468
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492469# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:402470def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492471 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:402472 black_list = (_EXCLUDED_PATHS +
2473 _TEST_CODE_EXCLUDED_PATHS +
2474 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042475 (r"^base[\\/]logging\.h$",
2476 r"^base[\\/]logging\.cc$",
Francois Doray177da2c2019-06-20 14:14:222477 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
Egor Paskoce145c42018-09-28 19:31:042478 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2479 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2480 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:122481 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:182482 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Patrick Monette0196be22019-05-10 03:33:152483 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:032484 r"diagnostics_writer\.cc$",
Patrick Monette0196be22019-05-10 03:33:152485 r"^chrome[\\/]chrome_cleaner[\\/].*",
2486 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
2487 r"^chrome[\\/]installer[\\/]setup[\\/].*",
Egor Paskoce145c42018-09-28 19:31:042488 r"^chromecast[\\/]",
2489 r"^cloud_print[\\/]",
2490 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:482491 r"dump_stability_report_main_win.cc$",
Sharon Yang5ee61d7e2020-04-15 23:39:052492 r"^components[\\/]media_control[\\/]renderer[\\/]"
2493 r"media_playback_options\.cc$",
Egor Paskoce145c42018-09-28 19:31:042494 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:462495 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:042496 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:462497 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:042498 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:252499 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:042500 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2501 r"^courgette[\\/]courgette_tool\.cc$",
2502 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:272503 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Wezd39b367f2019-11-05 00:37:002504 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332505 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:042506 r"^ipc[\\/]ipc_logging\.cc$",
2507 r"^native_client_sdk[\\/]",
2508 r"^remoting[\\/]base[\\/]logging\.h$",
2509 r"^remoting[\\/]host[\\/].*",
2510 r"^sandbox[\\/]linux[\\/].*",
DongJun Kimfebb3c22019-10-21 02:08:062511 r"^storage[\\/]browser[\\/]file_system[\\/]" +
Fabrice de Gans-Riberi570201a22019-01-17 23:32:332512 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:042513 r"^tools[\\/]",
2514 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2515 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Maksim Sisova4d1cfbe2020-06-16 07:58:372516 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2517 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2518 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402519 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492520 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:402521
thomasanderson625d3932017-03-29 07:16:582522 log_info = set([])
2523 printf = set([])
[email protected]85218562013-11-22 07:41:402524
2525 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582526 for _, line in f.ChangedContents():
2527 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2528 log_info.add(f.LocalPath())
2529 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2530 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372531
thomasanderson625d3932017-03-29 07:16:582532 if input_api.re.search(r"\bprintf\(", line):
2533 printf.add(f.LocalPath())
2534 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2535 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402536
2537 if log_info:
2538 return [output_api.PresubmitError(
2539 'These files spam the console log with LOG(INFO):',
2540 items=log_info)]
2541 if printf:
2542 return [output_api.PresubmitError(
2543 'These files spam the console log with printf/fprintf:',
2544 items=printf)]
2545 return []
2546
2547
[email protected]49aa76a2013-12-04 06:59:162548def _CheckForAnonymousVariables(input_api, output_api):
2549 """These types are all expected to hold locks while in scope and
2550 so should never be anonymous (which causes them to be immediately
2551 destroyed)."""
2552 they_who_must_be_named = [
2553 'base::AutoLock',
2554 'base::AutoReset',
2555 'base::AutoUnlock',
2556 'SkAutoAlphaRestore',
2557 'SkAutoBitmapShaderInstall',
2558 'SkAutoBlitterChoose',
2559 'SkAutoBounderCommit',
2560 'SkAutoCallProc',
2561 'SkAutoCanvasRestore',
2562 'SkAutoCommentBlock',
2563 'SkAutoDescriptor',
2564 'SkAutoDisableDirectionCheck',
2565 'SkAutoDisableOvalCheck',
2566 'SkAutoFree',
2567 'SkAutoGlyphCache',
2568 'SkAutoHDC',
2569 'SkAutoLockColors',
2570 'SkAutoLockPixels',
2571 'SkAutoMalloc',
2572 'SkAutoMaskFreeImage',
2573 'SkAutoMutexAcquire',
2574 'SkAutoPathBoundsUpdate',
2575 'SkAutoPDFRelease',
2576 'SkAutoRasterClipValidate',
2577 'SkAutoRef',
2578 'SkAutoTime',
2579 'SkAutoTrace',
2580 'SkAutoUnref',
2581 ]
2582 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2583 # bad: base::AutoLock(lock.get());
2584 # not bad: base::AutoLock lock(lock.get());
2585 bad_pattern = input_api.re.compile(anonymous)
2586 # good: new base::AutoLock(lock.get())
2587 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2588 errors = []
2589
2590 for f in input_api.AffectedFiles():
2591 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2592 continue
2593 for linenum, line in f.ChangedContents():
2594 if bad_pattern.search(line) and not good_pattern.search(line):
2595 errors.append('%s:%d' % (f.LocalPath(), linenum))
2596
2597 if errors:
2598 return [output_api.PresubmitError(
2599 'These lines create anonymous variables that need to be named:',
2600 items=errors)]
2601 return []
2602
2603
Peter Kasting4844e46e2018-02-23 07:27:102604def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532605 # Returns whether |template_str| is of the form <T, U...> for some types T
2606 # and U. Assumes that |template_str| is already in the form <...>.
2607 def HasMoreThanOneArg(template_str):
2608 # Level of <...> nesting.
2609 nesting = 0
2610 for c in template_str:
2611 if c == '<':
2612 nesting += 1
2613 elif c == '>':
2614 nesting -= 1
2615 elif c == ',' and nesting == 1:
2616 return True
2617 return False
2618
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492619 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102620 sources = lambda affected_file: input_api.FilterSourceFile(
2621 affected_file,
2622 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2623 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492624 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552625
2626 # Pattern to capture a single "<...>" block of template arguments. It can
2627 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2628 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2629 # latter would likely require counting that < and > match, which is not
2630 # expressible in regular languages. Should the need arise, one can introduce
2631 # limited counting (matching up to a total number of nesting depth), which
2632 # should cover all practical cases for already a low nesting limit.
2633 template_arg_pattern = (
2634 r'<[^>]*' # Opening block of <.
2635 r'>([^<]*>)?') # Closing block of >.
2636 # Prefix expressing that whatever follows is not already inside a <...>
2637 # block.
2638 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102639 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552640 not_inside_template_arg_pattern
2641 + r'\bstd::unique_ptr'
2642 + template_arg_pattern
2643 + r'\(\)')
2644
2645 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2646 template_arg_no_array_pattern = (
2647 r'<[^>]*[^]]' # Opening block of <.
2648 r'>([^(<]*[^]]>)?') # Closing block of >.
2649 # Prefix saying that what follows is the start of an expression.
2650 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2651 # Suffix saying that what follows are call parentheses with a non-empty list
2652 # of arguments.
2653 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532654 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552655 return_construct_pattern = input_api.re.compile(
2656 start_of_expr_pattern
2657 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532658 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552659 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532660 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552661 + nonempty_arg_list_pattern)
2662
Vaclav Brozek851d9602018-04-04 16:13:052663 problems_constructor = []
2664 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102665 for f in input_api.AffectedSourceFiles(sources):
2666 for line_number, line in f.ChangedContents():
2667 # Disallow:
2668 # return std::unique_ptr<T>(foo);
2669 # bar = std::unique_ptr<T>(foo);
2670 # But allow:
2671 # return std::unique_ptr<T[]>(foo);
2672 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532673 # And also allow cases when the second template argument is present. Those
2674 # cases cannot be handled by std::make_unique:
2675 # return std::unique_ptr<T, U>(foo);
2676 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052677 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532678 return_construct_result = return_construct_pattern.search(line)
2679 if return_construct_result and not HasMoreThanOneArg(
2680 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052681 problems_constructor.append(
2682 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102683 # Disallow:
2684 # std::unique_ptr<T>()
2685 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052686 problems_nullptr.append(
2687 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2688
2689 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162690 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052691 errors.append(output_api.PresubmitError(
2692 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162693 problems_nullptr))
2694 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052695 errors.append(output_api.PresubmitError(
2696 'The following files use explicit std::unique_ptr constructor.'
2697 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162698 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102699 return errors
2700
2701
[email protected]999261d2014-03-03 20:08:082702def _CheckUserActionUpdate(input_api, output_api):
2703 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522704 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082705 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522706 # If actions.xml is already included in the changelist, the PRESUBMIT
2707 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082708 return []
2709
[email protected]999261d2014-03-03 20:08:082710 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2711 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522712 current_actions = None
[email protected]999261d2014-03-03 20:08:082713 for f in input_api.AffectedFiles(file_filter=file_filter):
2714 for line_num, line in f.ChangedContents():
2715 match = input_api.re.search(action_re, line)
2716 if match:
[email protected]2f92dec2014-03-07 19:21:522717 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2718 # loaded only once.
2719 if not current_actions:
2720 with open('tools/metrics/actions/actions.xml') as actions_f:
2721 current_actions = actions_f.read()
2722 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082723 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522724 action = 'name="{0}"'.format(action_name)
2725 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082726 return [output_api.PresubmitPromptWarning(
2727 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522728 'tools/metrics/actions/actions.xml. Please run '
2729 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082730 % (f.LocalPath(), line_num, action_name))]
2731 return []
2732
2733
Daniel Cheng13ca61a882017-08-25 15:11:252734def _ImportJSONCommentEater(input_api):
2735 import sys
2736 sys.path = sys.path + [input_api.os_path.join(
2737 input_api.PresubmitLocalPath(),
2738 'tools', 'json_comment_eater')]
2739 import json_comment_eater
2740 return json_comment_eater
2741
2742
[email protected]99171a92014-06-03 08:44:472743def _GetJSONParseError(input_api, filename, eat_comments=True):
2744 try:
2745 contents = input_api.ReadFile(filename)
2746 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252747 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132748 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472749
2750 input_api.json.loads(contents)
2751 except ValueError as e:
2752 return e
2753 return None
2754
2755
2756def _GetIDLParseError(input_api, filename):
2757 try:
2758 contents = input_api.ReadFile(filename)
2759 idl_schema = input_api.os_path.join(
2760 input_api.PresubmitLocalPath(),
2761 'tools', 'json_schema_compiler', 'idl_schema.py')
2762 process = input_api.subprocess.Popen(
2763 [input_api.python_executable, idl_schema],
2764 stdin=input_api.subprocess.PIPE,
2765 stdout=input_api.subprocess.PIPE,
2766 stderr=input_api.subprocess.PIPE,
2767 universal_newlines=True)
2768 (_, error) = process.communicate(input=contents)
2769 return error or None
2770 except ValueError as e:
2771 return e
2772
2773
2774def _CheckParseErrors(input_api, output_api):
2775 """Check that IDL and JSON files do not contain syntax errors."""
2776 actions = {
2777 '.idl': _GetIDLParseError,
2778 '.json': _GetJSONParseError,
2779 }
[email protected]99171a92014-06-03 08:44:472780 # Most JSON files are preprocessed and support comments, but these do not.
2781 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042782 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472783 ]
2784 # Only run IDL checker on files in these directories.
2785 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042786 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2787 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472788 ]
2789
2790 def get_action(affected_file):
2791 filename = affected_file.LocalPath()
2792 return actions.get(input_api.os_path.splitext(filename)[1])
2793
[email protected]99171a92014-06-03 08:44:472794 def FilterFile(affected_file):
2795 action = get_action(affected_file)
2796 if not action:
2797 return False
2798 path = affected_file.LocalPath()
2799
Erik Staab2dd72b12020-04-16 15:03:402800 if _MatchesFile(input_api,
2801 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2802 path):
[email protected]99171a92014-06-03 08:44:472803 return False
2804
2805 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162806 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472807 return False
2808 return True
2809
2810 results = []
2811 for affected_file in input_api.AffectedFiles(
2812 file_filter=FilterFile, include_deletes=False):
2813 action = get_action(affected_file)
2814 kwargs = {}
2815 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162816 _MatchesFile(input_api, json_no_comments_patterns,
2817 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472818 kwargs['eat_comments'] = False
2819 parse_error = action(input_api,
2820 affected_file.AbsoluteLocalPath(),
2821 **kwargs)
2822 if parse_error:
2823 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2824 (affected_file.LocalPath(), parse_error)))
2825 return results
2826
2827
[email protected]760deea2013-12-10 19:33:492828def _CheckJavaStyle(input_api, output_api):
2829 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472830 import sys
[email protected]760deea2013-12-10 19:33:492831 original_sys_path = sys.path
2832 try:
2833 sys.path = sys.path + [input_api.os_path.join(
2834 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2835 import checkstyle
2836 finally:
2837 # Restore sys.path to what it was before.
2838 sys.path = original_sys_path
2839
2840 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092841 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512842 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492843
2844
Nate Fischerdfd9812e2019-07-18 22:03:002845def _CheckPythonDevilInit(input_api, output_api):
2846 """Checks to make sure devil is initialized correctly in python scripts."""
2847 script_common_initialize_pattern = input_api.re.compile(
2848 r'script_common\.InitializeEnvironment\(')
2849 devil_env_config_initialize = input_api.re.compile(
2850 r'devil_env\.config\.Initialize\(')
2851
2852 errors = []
2853
2854 sources = lambda affected_file: input_api.FilterSourceFile(
2855 affected_file,
2856 black_list=(_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST +
2857 (r'^build[\\/]android[\\/]devil_chromium\.py',
2858 r'^third_party[\\/].*',)),
2859 white_list=[r'.*\.py$'])
2860
2861 for f in input_api.AffectedSourceFiles(sources):
2862 for line_num, line in f.ChangedContents():
2863 if (script_common_initialize_pattern.search(line) or
2864 devil_env_config_initialize.search(line)):
2865 errors.append("%s:%d" % (f.LocalPath(), line_num))
2866
2867 results = []
2868
2869 if errors:
2870 results.append(output_api.PresubmitError(
2871 'Devil initialization should always be done using '
2872 'devil_chromium.Initialize() in the chromium project, to use better '
2873 'defaults for dependencies (ex. up-to-date version of adb).',
2874 errors))
2875
2876 return results
2877
2878
Sean Kau46e29bc2017-08-28 16:31:162879def _MatchesFile(input_api, patterns, path):
2880 for pattern in patterns:
2881 if input_api.re.search(pattern, path):
2882 return True
2883 return False
2884
2885
Daniel Cheng7052cdf2017-11-21 19:23:292886def _GetOwnersFilesToCheckForIpcOwners(input_api):
2887 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172888
Daniel Cheng7052cdf2017-11-21 19:23:292889 Returns:
2890 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2891 contain to cover IPC-related files with noparent reviewer rules.
2892 """
2893 # Whether or not a file affects IPC is (mostly) determined by a simple list
2894 # of filename patterns.
dchenge07de812016-06-20 19:27:172895 file_patterns = [
palmerb19a0932017-01-24 04:00:312896 # Legacy IPC:
dchenge07de812016-06-20 19:27:172897 '*_messages.cc',
2898 '*_messages*.h',
2899 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312900 # Mojo IPC:
dchenge07de812016-06-20 19:27:172901 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472902 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172903 '*_struct_traits*.*',
2904 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312905 '*.typemap',
2906 # Android native IPC:
2907 '*.aidl',
2908 # Blink uses a different file naming convention:
2909 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472910 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172911 '*StructTraits*.*',
2912 '*TypeConverter*.*',
2913 ]
2914
scottmg7a6ed5ba2016-11-04 18:22:042915 # These third_party directories do not contain IPCs, but contain files
2916 # matching the above patterns, which trigger false positives.
2917 exclude_paths = [
2918 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162919 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232920 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292921 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542922 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162923 # These files are just used to communicate between class loaders running
2924 # in the same process.
2925 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572926 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2927
scottmg7a6ed5ba2016-11-04 18:22:042928 ]
2929
dchenge07de812016-06-20 19:27:172930 # Dictionary mapping an OWNERS file path to Patterns.
2931 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2932 # rules ) to a PatternEntry.
2933 # PatternEntry is a dictionary with two keys:
2934 # - 'files': the files that are matched by this pattern
2935 # - 'rules': the per-file rules needed for this pattern
2936 # For example, if we expect OWNERS file to contain rules for *.mojom and
2937 # *_struct_traits*.*, Patterns might look like this:
2938 # {
2939 # '*.mojom': {
2940 # 'files': ...,
2941 # 'rules': [
2942 # 'per-file *.mojom=set noparent',
2943 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2944 # ],
2945 # },
2946 # '*_struct_traits*.*': {
2947 # 'files': ...,
2948 # 'rules': [
2949 # 'per-file *_struct_traits*.*=set noparent',
2950 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2951 # ],
2952 # },
2953 # }
2954 to_check = {}
2955
Daniel Cheng13ca61a882017-08-25 15:11:252956 def AddPatternToCheck(input_file, pattern):
2957 owners_file = input_api.os_path.join(
2958 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2959 if owners_file not in to_check:
2960 to_check[owners_file] = {}
2961 if pattern not in to_check[owners_file]:
2962 to_check[owners_file][pattern] = {
2963 'files': [],
2964 'rules': [
2965 'per-file %s=set noparent' % pattern,
2966 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2967 ]
2968 }
Vaclav Brozekd5de76a2018-03-17 07:57:502969 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252970
dchenge07de812016-06-20 19:27:172971 # Iterate through the affected files to see what we actually need to check
2972 # for. We should only nag patch authors about per-file rules if a file in that
2973 # directory would match that pattern. If a directory only contains *.mojom
2974 # files and no *_messages*.h files, we should only nag about rules for
2975 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252976 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262977 # Manifest files don't have a strong naming convention. Instead, try to find
2978 # affected .cc and .h files which look like they contain a manifest
2979 # definition.
2980 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2981 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2982 if (manifest_pattern.search(f.LocalPath()) and not
2983 test_manifest_pattern.search(f.LocalPath())):
2984 # We expect all actual service manifest files to contain at least one
2985 # qualified reference to service_manager::Manifest.
2986 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252987 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172988 for pattern in file_patterns:
2989 if input_api.fnmatch.fnmatch(
2990 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042991 skip = False
2992 for exclude in exclude_paths:
2993 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2994 skip = True
2995 break
2996 if skip:
2997 continue
Daniel Cheng13ca61a882017-08-25 15:11:252998 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172999 break
3000
Daniel Cheng7052cdf2017-11-21 19:23:293001 return to_check
3002
3003
Wez17c66962020-04-29 15:26:033004def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3005 """Adds OWNERS files to check for correct Fuchsia security owners."""
3006
3007 file_patterns = [
3008 # Component specifications.
3009 '*.cml', # Component Framework v2.
3010 '*.cmx', # Component Framework v1.
3011
3012 # Fuchsia IDL protocol specifications.
3013 '*.fidl',
3014 ]
3015
3016 def AddPatternToCheck(input_file, pattern):
3017 owners_file = input_api.os_path.join(
3018 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3019 if owners_file not in to_check:
3020 to_check[owners_file] = {}
3021 if pattern not in to_check[owners_file]:
3022 to_check[owners_file][pattern] = {
3023 'files': [],
3024 'rules': [
3025 'per-file %s=set noparent' % pattern,
3026 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3027 ]
3028 }
3029 to_check[owners_file][pattern]['files'].append(input_file)
3030
3031 # Iterate through the affected files to see what we actually need to check
3032 # for. We should only nag patch authors about per-file rules if a file in that
3033 # directory would match that pattern.
3034 for f in input_api.AffectedFiles(include_deletes=False):
3035 for pattern in file_patterns:
3036 if input_api.fnmatch.fnmatch(
3037 input_api.os_path.basename(f.LocalPath()), pattern):
3038 AddPatternToCheck(f, pattern)
3039 break
3040
3041 return to_check
3042
3043
3044def _CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293045 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3046 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033047 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293048
3049 if to_check:
3050 # If there are any OWNERS files to check, there are IPC-related changes in
3051 # this CL. Auto-CC the review list.
3052 output_api.AppendCC('[email protected]')
3053
3054 # Go through the OWNERS files to check, filtering out rules that are already
3055 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173056 for owners_file, patterns in to_check.iteritems():
3057 try:
3058 with file(owners_file) as f:
3059 lines = set(f.read().splitlines())
3060 for entry in patterns.itervalues():
3061 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3062 ]
3063 except IOError:
3064 # No OWNERS file, so all the rules are definitely missing.
3065 continue
3066
3067 # All the remaining lines weren't found in OWNERS files, so emit an error.
3068 errors = []
3069 for owners_file, patterns in to_check.iteritems():
3070 missing_lines = []
3071 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503072 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173073 missing_lines.extend(entry['rules'])
3074 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3075 if missing_lines:
3076 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053077 'Because of the presence of files:\n%s\n\n'
3078 '%s needs the following %d lines added:\n\n%s' %
3079 ('\n'.join(files), owners_file, len(missing_lines),
3080 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173081
3082 results = []
3083 if errors:
vabrf5ce3bf92016-07-11 14:52:413084 if input_api.is_committing:
3085 output = output_api.PresubmitError
3086 else:
3087 output = output_api.PresubmitPromptWarning
3088 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593089 'Found OWNERS files that need to be updated for IPC security ' +
3090 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173091 long_text='\n\n'.join(errors)))
3092
3093 return results
3094
3095
Robert Sesek2c905332020-05-06 23:17:133096def _GetFilesUsingSecurityCriticalFunctions(input_api):
3097 """Checks affected files for changes to security-critical calls. This
3098 function checks the full change diff, to catch both additions/changes
3099 and removals.
3100
3101 Returns a dict keyed by file name, and the value is a set of detected
3102 functions.
3103 """
3104 # Map of function pretty name (displayed in an error) to the pattern to
3105 # match it with.
3106 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373107 'content::GetServiceSandboxType<>()':
3108 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133109 }
3110 _PATTERNS_TO_CHECK = {
3111 k: input_api.re.compile(v)
3112 for k, v in _PATTERNS_TO_CHECK.items()
3113 }
3114
3115 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3116 files_to_functions = {}
3117 for f in input_api.AffectedFiles():
3118 diff = f.GenerateScmDiff()
3119 for line in diff.split('\n'):
3120 # Not using just RightHandSideLines() because removing a
3121 # call to a security-critical function can be just as important
3122 # as adding or changing the arguments.
3123 if line.startswith('-') or (line.startswith('+') and
3124 not line.startswith('++')):
3125 for name, pattern in _PATTERNS_TO_CHECK.items():
3126 if pattern.search(line):
3127 path = f.LocalPath()
3128 if not path in files_to_functions:
3129 files_to_functions[path] = set()
3130 files_to_functions[path].add(name)
3131 return files_to_functions
3132
3133
3134def _CheckSecurityChanges(input_api, output_api):
3135 """Checks that changes involving security-critical functions are reviewed
3136 by the security team.
3137 """
3138 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3139 if len(files_to_functions):
3140 owners_db = input_api.owners_db
3141 owner_email, reviewers = (
3142 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3143 input_api,
3144 owners_db.email_regexp,
3145 approval_needed=input_api.is_committing))
3146
3147 # Load the OWNERS file for security changes.
3148 owners_file = 'ipc/SECURITY_OWNERS'
3149 security_owners = owners_db.owners_rooted_at_file(owners_file)
3150
3151 has_security_owner = any([owner in reviewers for owner in security_owners])
3152 if not has_security_owner:
3153 msg = 'The following files change calls to security-sensive functions\n' \
3154 'that need to be reviewed by {}.\n'.format(owners_file)
3155 for path, names in files_to_functions.items():
3156 msg += ' {}\n'.format(path)
3157 for name in names:
3158 msg += ' {}\n'.format(name)
3159 msg += '\n'
3160
3161 if input_api.is_committing:
3162 output = output_api.PresubmitError
3163 else:
3164 output = output_api.PresubmitNotifyResult
3165 return [output(msg)]
3166
3167 return []
3168
3169
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263170def _CheckSetNoParent(input_api, output_api):
3171 """Checks that set noparent is only used together with an OWNERS file in
3172 //build/OWNERS.setnoparent (see also
3173 //docs/code_reviews.md#owners-files-details)
3174 """
3175 errors = []
3176
3177 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3178 allowed_owners_files = set()
3179 with open(allowed_owners_files_file, 'r') as f:
3180 for line in f:
3181 line = line.strip()
3182 if not line or line.startswith('#'):
3183 continue
3184 allowed_owners_files.add(line)
3185
3186 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3187
3188 for f in input_api.AffectedFiles(include_deletes=False):
3189 if not f.LocalPath().endswith('OWNERS'):
3190 continue
3191
3192 found_owners_files = set()
3193 found_set_noparent_lines = dict()
3194
3195 # Parse the OWNERS file.
3196 for lineno, line in enumerate(f.NewContents(), 1):
3197 line = line.strip()
3198 if line.startswith('set noparent'):
3199 found_set_noparent_lines[''] = lineno
3200 if line.startswith('file://'):
3201 if line in allowed_owners_files:
3202 found_owners_files.add('')
3203 if line.startswith('per-file'):
3204 match = per_file_pattern.match(line)
3205 if match:
3206 glob = match.group(1).strip()
3207 directive = match.group(2).strip()
3208 if directive == 'set noparent':
3209 found_set_noparent_lines[glob] = lineno
3210 if directive.startswith('file://'):
3211 if directive in allowed_owners_files:
3212 found_owners_files.add(glob)
3213
3214 # Check that every set noparent line has a corresponding file:// line
3215 # listed in build/OWNERS.setnoparent.
3216 for set_noparent_line in found_set_noparent_lines:
3217 if set_noparent_line in found_owners_files:
3218 continue
3219 errors.append(' %s:%d' % (f.LocalPath(),
3220 found_set_noparent_lines[set_noparent_line]))
3221
3222 results = []
3223 if errors:
3224 if input_api.is_committing:
3225 output = output_api.PresubmitError
3226 else:
3227 output = output_api.PresubmitPromptWarning
3228 results.append(output(
3229 'Found the following "set noparent" restrictions in OWNERS files that '
3230 'do not include owners from build/OWNERS.setnoparent:',
3231 long_text='\n\n'.join(errors)))
3232 return results
3233
3234
jbriance9e12f162016-11-25 07:57:503235def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313236 """Checks that added or removed lines in non third party affected
3237 header files do not lead to new useless class or struct forward
3238 declaration.
jbriance9e12f162016-11-25 07:57:503239 """
3240 results = []
3241 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3242 input_api.re.MULTILINE)
3243 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3244 input_api.re.MULTILINE)
3245 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313246 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193247 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493248 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313249 continue
3250
jbriance9e12f162016-11-25 07:57:503251 if not f.LocalPath().endswith('.h'):
3252 continue
3253
3254 contents = input_api.ReadFile(f)
3255 fwd_decls = input_api.re.findall(class_pattern, contents)
3256 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3257
3258 useless_fwd_decls = []
3259 for decl in fwd_decls:
3260 count = sum(1 for _ in input_api.re.finditer(
3261 r'\b%s\b' % input_api.re.escape(decl), contents))
3262 if count == 1:
3263 useless_fwd_decls.append(decl)
3264
3265 if not useless_fwd_decls:
3266 continue
3267
3268 for line in f.GenerateScmDiff().splitlines():
3269 if (line.startswith('-') and not line.startswith('--') or
3270 line.startswith('+') and not line.startswith('++')):
3271 for decl in useless_fwd_decls:
3272 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3273 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243274 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503275 (f.LocalPath(), decl)))
3276 useless_fwd_decls.remove(decl)
3277
3278 return results
3279
Jinsong Fan91ebbbd2019-04-16 14:57:173280def _CheckAndroidDebuggableBuild(input_api, output_api):
3281 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3282 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3283 this is a debuggable build of Android.
3284 """
3285 build_type_check_pattern = input_api.re.compile(
3286 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3287
3288 errors = []
3289
3290 sources = lambda affected_file: input_api.FilterSourceFile(
3291 affected_file,
3292 black_list=(_EXCLUDED_PATHS +
3293 _TEST_CODE_EXCLUDED_PATHS +
3294 input_api.DEFAULT_BLACK_LIST +
3295 (r"^android_webview[\\/]support_library[\\/]"
3296 "boundary_interfaces[\\/]",
3297 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3298 r'^third_party[\\/].*',
3299 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3300 r"webview[\\/]chromium[\\/]License.*",)),
3301 white_list=[r'.*\.java$'])
3302
3303 for f in input_api.AffectedSourceFiles(sources):
3304 for line_num, line in f.ChangedContents():
3305 if build_type_check_pattern.search(line):
3306 errors.append("%s:%d" % (f.LocalPath(), line_num))
3307
3308 results = []
3309
3310 if errors:
3311 results.append(output_api.PresubmitPromptWarning(
3312 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3313 ' Please use BuildInfo.isDebugAndroid() instead.',
3314 errors))
3315
3316 return results
jbriance9e12f162016-11-25 07:57:503317
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493318# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293319def _CheckAndroidToastUsage(input_api, output_api):
3320 """Checks that code uses org.chromium.ui.widget.Toast instead of
3321 android.widget.Toast (Chromium Toast doesn't force hardware
3322 acceleration on low-end devices, saving memory).
3323 """
3324 toast_import_pattern = input_api.re.compile(
3325 r'^import android\.widget\.Toast;$')
3326
3327 errors = []
3328
3329 sources = lambda affected_file: input_api.FilterSourceFile(
3330 affected_file,
3331 black_list=(_EXCLUDED_PATHS +
3332 _TEST_CODE_EXCLUDED_PATHS +
3333 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043334 (r'^chromecast[\\/].*',
3335 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493336 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293337
3338 for f in input_api.AffectedSourceFiles(sources):
3339 for line_num, line in f.ChangedContents():
3340 if toast_import_pattern.search(line):
3341 errors.append("%s:%d" % (f.LocalPath(), line_num))
3342
3343 results = []
3344
3345 if errors:
3346 results.append(output_api.PresubmitError(
3347 'android.widget.Toast usage is detected. Android toasts use hardware'
3348 ' acceleration, and can be\ncostly on low-end devices. Please use'
3349 ' org.chromium.ui.widget.Toast instead.\n'
3350 'Contact [email protected] if you have any questions.',
3351 errors))
3352
3353 return results
3354
3355
dgnaa68d5e2015-06-10 10:08:223356def _CheckAndroidCrLogUsage(input_api, output_api):
3357 """Checks that new logs using org.chromium.base.Log:
3358 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513359 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223360 """
pkotwicza1dd0b002016-05-16 14:41:043361
torne89540622017-03-24 19:41:303362 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043363 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303364 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043365 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303366 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043367 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3368 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093369 # The customtabs_benchmark is a small app that does not depend on Chromium
3370 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043371 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043372 ]
3373
dgnaa68d5e2015-06-10 10:08:223374 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123375 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3376 class_in_base_pattern = input_api.re.compile(
3377 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3378 has_some_log_import_pattern = input_api.re.compile(
3379 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223380 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553381 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223382 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463383 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553384 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223385
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463386 REF_MSG = ('See docs/android_logging.md for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493387 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:043388 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123389
dgnaa68d5e2015-06-10 10:08:223390 tag_decl_errors = []
3391 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123392 tag_errors = []
dgn38736db2015-09-18 19:20:513393 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123394 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223395
3396 for f in input_api.AffectedSourceFiles(sources):
3397 file_content = input_api.ReadFile(f)
3398 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223399 # Per line checks
dgn87d9fb62015-06-12 09:15:123400 if (cr_log_import_pattern.search(file_content) or
3401 (class_in_base_pattern.search(file_content) and
3402 not has_some_log_import_pattern.search(file_content))):
3403 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223404 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553405 if rough_log_decl_pattern.search(line):
3406 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223407
3408 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123409 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223410 if match:
3411 has_modified_logs = True
3412
3413 # Make sure it uses "TAG"
3414 if not match.group('tag') == 'TAG':
3415 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123416 else:
3417 # Report non cr Log function calls in changed lines
3418 for line_num, line in f.ChangedContents():
3419 if log_call_pattern.search(line):
3420 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223421
3422 # Per file checks
3423 if has_modified_logs:
3424 # Make sure the tag is using the "cr" prefix and is not too long
3425 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513426 tag_name = match.group('name') if match else None
3427 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223428 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513429 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223430 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513431 elif '.' in tag_name:
3432 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223433
3434 results = []
3435 if tag_decl_errors:
3436 results.append(output_api.PresubmitPromptWarning(
3437 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513438 '"private static final String TAG = "<package tag>".\n'
3439 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223440 tag_decl_errors))
3441
3442 if tag_length_errors:
3443 results.append(output_api.PresubmitError(
3444 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513445 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223446 tag_length_errors))
3447
3448 if tag_errors:
3449 results.append(output_api.PresubmitPromptWarning(
3450 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3451 tag_errors))
3452
dgn87d9fb62015-06-12 09:15:123453 if util_log_errors:
dgn4401aa52015-04-29 16:26:173454 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123455 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3456 util_log_errors))
3457
dgn38736db2015-09-18 19:20:513458 if tag_with_dot_errors:
3459 results.append(output_api.PresubmitPromptWarning(
3460 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3461 tag_with_dot_errors))
3462
dgn4401aa52015-04-29 16:26:173463 return results
3464
3465
Yoland Yanb92fa522017-08-28 17:37:063466def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3467 """Checks that junit.framework.* is no longer used."""
3468 deprecated_junit_framework_pattern = input_api.re.compile(
3469 r'^import junit\.framework\..*;',
3470 input_api.re.MULTILINE)
3471 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493472 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063473 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133474 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063475 for line_num, line in f.ChangedContents():
3476 if deprecated_junit_framework_pattern.search(line):
3477 errors.append("%s:%d" % (f.LocalPath(), line_num))
3478
3479 results = []
3480 if errors:
3481 results.append(output_api.PresubmitError(
3482 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3483 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3484 ' if you have any question.', errors))
3485 return results
3486
3487
3488def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3489 """Checks that if new Java test classes have inheritance.
3490 Either the new test class is JUnit3 test or it is a JUnit4 test class
3491 with a base class, either case is undesirable.
3492 """
3493 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3494
3495 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493496 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:063497 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133498 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063499 if not f.OldContents():
3500 class_declaration_start_flag = False
3501 for line_num, line in f.ChangedContents():
3502 if class_declaration_pattern.search(line):
3503 class_declaration_start_flag = True
3504 if class_declaration_start_flag and ' extends ' in line:
3505 errors.append('%s:%d' % (f.LocalPath(), line_num))
3506 if '{' in line:
3507 class_declaration_start_flag = False
3508
3509 results = []
3510 if errors:
3511 results.append(output_api.PresubmitPromptWarning(
3512 'The newly created files include Test classes that inherits from base'
3513 ' class. Please do not use inheritance in JUnit4 tests or add new'
3514 ' JUnit3 tests. Contact [email protected] if you have any'
3515 ' questions.', errors))
3516 return results
3517
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203518
yolandyan45001472016-12-21 21:12:423519def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3520 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3521 deprecated_annotation_import_pattern = input_api.re.compile(
3522 r'^import android\.test\.suitebuilder\.annotation\..*;',
3523 input_api.re.MULTILINE)
3524 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493525 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:423526 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133527 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423528 for line_num, line in f.ChangedContents():
3529 if deprecated_annotation_import_pattern.search(line):
3530 errors.append("%s:%d" % (f.LocalPath(), line_num))
3531
3532 results = []
3533 if errors:
3534 results.append(output_api.PresubmitError(
3535 'Annotations in android.test.suitebuilder.annotation have been'
3536 ' deprecated since API level 24. Please use android.support.test.filters'
3537 ' from //third_party/android_support_test_runner:runner_java instead.'
3538 ' Contact [email protected] if you have any questions.', errors))
3539 return results
3540
3541
agrieve7b6479d82015-10-07 14:24:223542def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3543 """Checks if MDPI assets are placed in a correct directory."""
3544 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3545 ('/res/drawable/' in f.LocalPath() or
3546 '/res/drawable-ldrtl/' in f.LocalPath()))
3547 errors = []
3548 for f in input_api.AffectedFiles(include_deletes=False,
3549 file_filter=file_filter):
3550 errors.append(' %s' % f.LocalPath())
3551
3552 results = []
3553 if errors:
3554 results.append(output_api.PresubmitError(
3555 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3556 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3557 '/res/drawable-ldrtl/.\n'
3558 'Contact [email protected] if you have questions.', errors))
3559 return results
3560
3561
Nate Fischer535972b2017-09-16 01:06:183562def _CheckAndroidWebkitImports(input_api, output_api):
3563 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353564 android.webview.ValueCallback except in the WebView glue layer
3565 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183566 """
3567 valuecallback_import_pattern = input_api.re.compile(
3568 r'^import android\.webkit\.ValueCallback;$')
3569
3570 errors = []
3571
3572 sources = lambda affected_file: input_api.FilterSourceFile(
3573 affected_file,
3574 black_list=(_EXCLUDED_PATHS +
3575 _TEST_CODE_EXCLUDED_PATHS +
3576 input_api.DEFAULT_BLACK_LIST +
Bo Liubfde1c02019-09-24 23:08:353577 (r'^android_webview[\\/]glue[\\/].*',
3578 r'^weblayer[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493579 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183580
3581 for f in input_api.AffectedSourceFiles(sources):
3582 for line_num, line in f.ChangedContents():
3583 if valuecallback_import_pattern.search(line):
3584 errors.append("%s:%d" % (f.LocalPath(), line_num))
3585
3586 results = []
3587
3588 if errors:
3589 results.append(output_api.PresubmitError(
3590 'android.webkit.ValueCallback usage is detected outside of the glue'
3591 ' layer. To stay compatible with the support library, android.webkit.*'
3592 ' classes should only be used inside the glue layer and'
3593 ' org.chromium.base.Callback should be used instead.',
3594 errors))
3595
3596 return results
3597
3598
Becky Zhou7c69b50992018-12-10 19:37:573599def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3600 """Checks Android XML styles """
3601 import sys
3602 original_sys_path = sys.path
3603 try:
3604 sys.path = sys.path + [input_api.os_path.join(
3605 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3606 import checkxmlstyle
3607 finally:
3608 # Restore sys.path to what it was before.
3609 sys.path = original_sys_path
3610
3611 if is_check_on_upload:
3612 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3613 else:
3614 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3615
3616
agrievef32bcc72016-04-04 14:57:403617class PydepsChecker(object):
3618 def __init__(self, input_api, pydeps_files):
3619 self._file_cache = {}
3620 self._input_api = input_api
3621 self._pydeps_files = pydeps_files
3622
3623 def _LoadFile(self, path):
3624 """Returns the list of paths within a .pydeps file relative to //."""
3625 if path not in self._file_cache:
3626 with open(path) as f:
3627 self._file_cache[path] = f.read()
3628 return self._file_cache[path]
3629
3630 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3631 """Returns an interable of paths within the .pydep, relativized to //."""
3632 os_path = self._input_api.os_path
3633 pydeps_dir = os_path.dirname(pydeps_path)
3634 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3635 if not l.startswith('*'))
3636 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3637
3638 def _CreateFilesToPydepsMap(self):
3639 """Returns a map of local_path -> list_of_pydeps."""
3640 ret = {}
3641 for pydep_local_path in self._pydeps_files:
3642 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3643 ret.setdefault(path, []).append(pydep_local_path)
3644 return ret
3645
3646 def ComputeAffectedPydeps(self):
3647 """Returns an iterable of .pydeps files that might need regenerating."""
3648 affected_pydeps = set()
3649 file_to_pydeps_map = None
3650 for f in self._input_api.AffectedFiles(include_deletes=True):
3651 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463652 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3653 # subrepositories. We can't figure out which files change, so re-check
3654 # all files.
3655 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383656 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3657 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403658 return self._pydeps_files
3659 elif local_path.endswith('.pydeps'):
3660 if local_path in self._pydeps_files:
3661 affected_pydeps.add(local_path)
3662 elif local_path.endswith('.py'):
3663 if file_to_pydeps_map is None:
3664 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3665 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3666 return affected_pydeps
3667
3668 def DetermineIfStale(self, pydeps_path):
3669 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413670 import difflib
John Budorick47ca3fe2018-02-10 00:53:103671 import os
3672
agrievef32bcc72016-04-04 14:57:403673 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033674 if old_pydeps_data:
3675 cmd = old_pydeps_data[1][1:].strip()
3676 old_contents = old_pydeps_data[2:]
3677 else:
3678 # A default cmd that should work in most cases (as long as pydeps filename
3679 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3680 # file is empty/new.
3681 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3682 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3683 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103684 env = dict(os.environ)
3685 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403686 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103687 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413688 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033689 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413690 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403691
3692
Tibor Goldschwendt360793f72019-06-25 18:23:493693def _ParseGclientArgs():
3694 args = {}
3695 with open('build/config/gclient_args.gni', 'r') as f:
3696 for line in f:
3697 line = line.strip()
3698 if not line or line.startswith('#'):
3699 continue
3700 attribute, value = line.split('=')
3701 args[attribute.strip()] = value.strip()
3702 return args
3703
3704
agrievef32bcc72016-04-04 14:57:403705def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
3706 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403707 # This check is for Python dependency lists (.pydeps files), and involves
3708 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3709 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283710 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003711 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493712 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403713 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403714 results = []
3715 # First, check for new / deleted .pydeps.
3716 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033717 # Check whether we are running the presubmit check for a file in src.
3718 # f.LocalPath is relative to repo (src, or internal repo).
3719 # os_path.exists is relative to src repo.
3720 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3721 # to src and we can conclude that the pydeps is in src.
3722 if input_api.os_path.exists(f.LocalPath()):
3723 if f.LocalPath().endswith('.pydeps'):
3724 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3725 results.append(output_api.PresubmitError(
3726 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3727 'remove %s' % f.LocalPath()))
3728 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3729 results.append(output_api.PresubmitError(
3730 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3731 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403732
3733 if results:
3734 return results
3735
Mohamed Heikal7cd4d8312020-06-16 16:49:403736 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3737 affected_pydeps = set(checker.ComputeAffectedPydeps())
3738 affected_android_pydeps = affected_pydeps.intersection(
3739 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3740 if affected_android_pydeps and not is_android:
3741 results.append(output_api.PresubmitPromptOrNotify(
3742 'You have changed python files that may affect pydeps for android\n'
3743 'specific scripts. However, the relevant presumbit check cannot be\n'
3744 'run because you are not using an Android checkout. To validate that\n'
3745 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3746 'use the android-internal-presubmit optional trybot.\n'
3747 'Possibly stale pydeps files:\n{}'.format(
3748 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403749
Mohamed Heikal7cd4d8312020-06-16 16:49:403750 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3751 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403752 try:
phajdan.jr0d9878552016-11-04 10:49:413753 result = checker.DetermineIfStale(pydep_path)
3754 if result:
3755 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403756 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413757 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3758 'To regenerate, run:\n\n %s' %
3759 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403760 except input_api.subprocess.CalledProcessError as error:
3761 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3762 long_text=error.output)]
3763
3764 return results
3765
3766
glidere61efad2015-02-18 17:39:433767def _CheckSingletonInHeaders(input_api, output_api):
3768 """Checks to make sure no header files have |Singleton<|."""
3769 def FileFilter(affected_file):
3770 # It's ok for base/memory/singleton.h to have |Singleton<|.
3771 black_list = (_EXCLUDED_PATHS +
3772 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:043773 (r"^base[\\/]memory[\\/]singleton\.h$",
3774 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:473775 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:433776 return input_api.FilterSourceFile(affected_file, black_list=black_list)
3777
sergeyu34d21222015-09-16 00:11:443778 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433779 files = []
3780 for f in input_api.AffectedSourceFiles(FileFilter):
3781 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3782 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3783 contents = input_api.ReadFile(f)
3784 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243785 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433786 pattern.search(line)):
3787 files.append(f)
3788 break
3789
3790 if files:
yolandyandaabc6d2016-04-18 18:29:393791 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443792 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433793 'Please move them to an appropriate source file so that the ' +
3794 'template gets instantiated in a single compilation unit.',
3795 files) ]
3796 return []
3797
3798
[email protected]fd20b902014-05-09 02:14:533799_DEPRECATED_CSS = [
3800 # Values
3801 ( "-webkit-box", "flex" ),
3802 ( "-webkit-inline-box", "inline-flex" ),
3803 ( "-webkit-flex", "flex" ),
3804 ( "-webkit-inline-flex", "inline-flex" ),
3805 ( "-webkit-min-content", "min-content" ),
3806 ( "-webkit-max-content", "max-content" ),
3807
3808 # Properties
3809 ( "-webkit-background-clip", "background-clip" ),
3810 ( "-webkit-background-origin", "background-origin" ),
3811 ( "-webkit-background-size", "background-size" ),
3812 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443813 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533814
3815 # Functions
3816 ( "-webkit-gradient", "gradient" ),
3817 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3818 ( "-webkit-linear-gradient", "linear-gradient" ),
3819 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3820 ( "-webkit-radial-gradient", "radial-gradient" ),
3821 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3822]
3823
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203824
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493825# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:243826def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533827 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253828 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343829 documentation and iOS CSS for dom distiller
3830 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253831 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533832 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493833 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:253834 black_list = (_EXCLUDED_PATHS +
3835 _TEST_CODE_EXCLUDED_PATHS +
3836 input_api.DEFAULT_BLACK_LIST +
3837 (r"^chrome/common/extensions/docs",
3838 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:343839 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:443840 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:253841 r"^native_client_sdk"))
3842 file_filter = lambda f: input_api.FilterSourceFile(
3843 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:533844 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3845 for line_num, line in fpath.ChangedContents():
3846 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023847 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533848 results.append(output_api.PresubmitError(
3849 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3850 (fpath.LocalPath(), line_num, deprecated_value, value)))
3851 return results
3852
mohan.reddyf21db962014-10-16 12:26:473853
rlanday6802cf632017-05-30 17:48:363854def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363855 bad_files = {}
3856 for f in input_api.AffectedFiles(include_deletes=False):
3857 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493858 not f.LocalPath().startswith('third_party/blink') and
3859 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363860 continue
3861
Daniel Bratell65b033262019-04-23 08:17:063862 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363863 continue
3864
Vaclav Brozekd5de76a2018-03-17 07:57:503865 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363866 if "#include" in line and "../" in line]
3867 if not relative_includes:
3868 continue
3869 bad_files[f.LocalPath()] = relative_includes
3870
3871 if not bad_files:
3872 return []
3873
3874 error_descriptions = []
3875 for file_path, bad_lines in bad_files.iteritems():
3876 error_description = file_path
3877 for line in bad_lines:
3878 error_description += '\n ' + line
3879 error_descriptions.append(error_description)
3880
3881 results = []
3882 results.append(output_api.PresubmitError(
3883 'You added one or more relative #include paths (including "../").\n'
3884 'These shouldn\'t be used because they can be used to include headers\n'
3885 'from code that\'s not correctly specified as a dependency in the\n'
3886 'relevant BUILD.gn file(s).',
3887 error_descriptions))
3888
3889 return results
3890
Takeshi Yoshinoe387aa32017-08-02 13:16:133891
Daniel Bratell65b033262019-04-23 08:17:063892def _CheckForCcIncludes(input_api, output_api):
3893 """Check that nobody tries to include a cc file. It's a relatively
3894 common error which results in duplicate symbols in object
3895 files. This may not always break the build until someone later gets
3896 very confusing linking errors."""
3897 results = []
3898 for f in input_api.AffectedFiles(include_deletes=False):
3899 # We let third_party code do whatever it wants
3900 if (f.LocalPath().startswith('third_party') and
3901 not f.LocalPath().startswith('third_party/blink') and
3902 not f.LocalPath().startswith('third_party\\blink')):
3903 continue
3904
3905 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3906 continue
3907
3908 for _, line in f.ChangedContents():
3909 if line.startswith('#include "'):
3910 included_file = line.split('"')[1]
3911 if _IsCPlusPlusFile(input_api, included_file):
3912 # The most common naming for external files with C++ code,
3913 # apart from standard headers, is to call them foo.inc, but
3914 # Chromium sometimes uses foo-inc.cc so allow that as well.
3915 if not included_file.endswith(('.h', '-inc.cc')):
3916 results.append(output_api.PresubmitError(
3917 'Only header files or .inc files should be included in other\n'
3918 'C++ files. Compiling the contents of a cc file more than once\n'
3919 'will cause duplicate information in the build which may later\n'
3920 'result in strange link_errors.\n' +
3921 f.LocalPath() + ':\n ' +
3922 line))
3923
3924 return results
3925
3926
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203927def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3928 if not isinstance(key, ast.Str):
3929 return 'Key at line %d must be a string literal' % key.lineno
3930 if not isinstance(value, ast.Dict):
3931 return 'Value at line %d must be a dict' % value.lineno
3932 if len(value.keys) != 1:
3933 return 'Dict at line %d must have single entry' % value.lineno
3934 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3935 return (
3936 'Entry at line %d must have a string literal \'filepath\' as key' %
3937 value.lineno)
3938 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133939
Takeshi Yoshinoe387aa32017-08-02 13:16:133940
Sergey Ulanov4af16052018-11-08 02:41:463941def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203942 if not isinstance(key, ast.Str):
3943 return 'Key at line %d must be a string literal' % key.lineno
3944 if not isinstance(value, ast.List):
3945 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463946 for element in value.elts:
3947 if not isinstance(element, ast.Str):
3948 return 'Watchlist elements on line %d is not a string' % key.lineno
3949 if not email_regex.match(element.s):
3950 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3951 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203952 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133953
Takeshi Yoshinoe387aa32017-08-02 13:16:133954
Sergey Ulanov4af16052018-11-08 02:41:463955def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203956 mismatch_template = (
3957 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3958 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133959
Sergey Ulanov4af16052018-11-08 02:41:463960 email_regex = input_api.re.compile(
3961 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3962
3963 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203964 i = 0
3965 last_key = ''
3966 while True:
3967 if i >= len(wd_dict.keys):
3968 if i >= len(w_dict.keys):
3969 return None
3970 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3971 elif i >= len(w_dict.keys):
3972 return (
3973 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133974
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203975 wd_key = wd_dict.keys[i]
3976 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133977
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203978 result = _CheckWatchlistDefinitionsEntrySyntax(
3979 wd_key, wd_dict.values[i], ast)
3980 if result is not None:
3981 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133982
Sergey Ulanov4af16052018-11-08 02:41:463983 result = _CheckWatchlistsEntrySyntax(
3984 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203985 if result is not None:
3986 return 'Bad entry in WATCHLISTS dict: %s' % result
3987
3988 if wd_key.s != w_key.s:
3989 return mismatch_template % (
3990 '%s at line %d' % (wd_key.s, wd_key.lineno),
3991 '%s at line %d' % (w_key.s, w_key.lineno))
3992
3993 if wd_key.s < last_key:
3994 return (
3995 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3996 (wd_key.lineno, w_key.lineno))
3997 last_key = wd_key.s
3998
3999 i = i + 1
4000
4001
Sergey Ulanov4af16052018-11-08 02:41:464002def _CheckWATCHLISTSSyntax(expression, input_api):
4003 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204004 if not isinstance(expression, ast.Expression):
4005 return 'WATCHLISTS file must contain a valid expression'
4006 dictionary = expression.body
4007 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4008 return 'WATCHLISTS file must have single dict with exactly two entries'
4009
4010 first_key = dictionary.keys[0]
4011 first_value = dictionary.values[0]
4012 second_key = dictionary.keys[1]
4013 second_value = dictionary.values[1]
4014
4015 if (not isinstance(first_key, ast.Str) or
4016 first_key.s != 'WATCHLIST_DEFINITIONS' or
4017 not isinstance(first_value, ast.Dict)):
4018 return (
4019 'The first entry of the dict in WATCHLISTS file must be '
4020 'WATCHLIST_DEFINITIONS dict')
4021
4022 if (not isinstance(second_key, ast.Str) or
4023 second_key.s != 'WATCHLISTS' or
4024 not isinstance(second_value, ast.Dict)):
4025 return (
4026 'The second entry of the dict in WATCHLISTS file must be '
4027 'WATCHLISTS dict')
4028
Sergey Ulanov4af16052018-11-08 02:41:464029 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134030
4031
4032def _CheckWATCHLISTS(input_api, output_api):
4033 for f in input_api.AffectedFiles(include_deletes=False):
4034 if f.LocalPath() == 'WATCHLISTS':
4035 contents = input_api.ReadFile(f, 'r')
4036
4037 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204038 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134039 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204040 # Get an AST tree for it and scan the tree for detailed style checking.
4041 expression = input_api.ast.parse(
4042 contents, filename='WATCHLISTS', mode='eval')
4043 except ValueError as e:
4044 return [output_api.PresubmitError(
4045 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4046 except SyntaxError as e:
4047 return [output_api.PresubmitError(
4048 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4049 except TypeError as e:
4050 return [output_api.PresubmitError(
4051 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134052
Sergey Ulanov4af16052018-11-08 02:41:464053 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204054 if result is not None:
4055 return [output_api.PresubmitError(result)]
4056 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134057
4058 return []
4059
4060
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194061def _CheckNewHeaderWithoutGnChange(input_api, output_api):
4062 """Checks that newly added header files have corresponding GN changes.
4063 Note that this is only a heuristic. To be precise, run script:
4064 build/check_gn_headers.py.
4065 """
4066
4067 def headers(f):
4068 return input_api.FilterSourceFile(
4069 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
4070
4071 new_headers = []
4072 for f in input_api.AffectedSourceFiles(headers):
4073 if f.Action() != 'A':
4074 continue
4075 new_headers.append(f.LocalPath())
4076
4077 def gn_files(f):
4078 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
4079
4080 all_gn_changed_contents = ''
4081 for f in input_api.AffectedSourceFiles(gn_files):
4082 for _, line in f.ChangedContents():
4083 all_gn_changed_contents += line
4084
4085 problems = []
4086 for header in new_headers:
4087 basename = input_api.os_path.basename(header)
4088 if basename not in all_gn_changed_contents:
4089 problems.append(header)
4090
4091 if problems:
4092 return [output_api.PresubmitPromptWarning(
4093 'Missing GN changes for new header files', items=sorted(problems),
4094 long_text='Please double check whether newly added header files need '
4095 'corresponding changes in gn or gni files.\nThis checking is only a '
4096 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4097 'Read https://crbug.com/661774 for more info.')]
4098 return []
4099
4100
Michael Giuffridad3bc8672018-10-25 22:48:024101def _CheckCorrectProductNameInMessages(input_api, output_api):
4102 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4103
4104 This assumes we won't intentionally reference one product from the other
4105 product.
4106 """
4107 all_problems = []
4108 test_cases = [{
4109 "filename_postfix": "google_chrome_strings.grd",
4110 "correct_name": "Chrome",
4111 "incorrect_name": "Chromium",
4112 }, {
4113 "filename_postfix": "chromium_strings.grd",
4114 "correct_name": "Chromium",
4115 "incorrect_name": "Chrome",
4116 }]
4117
4118 for test_case in test_cases:
4119 problems = []
4120 filename_filter = lambda x: x.LocalPath().endswith(
4121 test_case["filename_postfix"])
4122
4123 # Check each new line. Can yield false positives in multiline comments, but
4124 # easier than trying to parse the XML because messages can have nested
4125 # children, and associating message elements with affected lines is hard.
4126 for f in input_api.AffectedSourceFiles(filename_filter):
4127 for line_num, line in f.ChangedContents():
4128 if "<message" in line or "<!--" in line or "-->" in line:
4129 continue
4130 if test_case["incorrect_name"] in line:
4131 problems.append(
4132 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4133
4134 if problems:
4135 message = (
4136 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4137 % (test_case["correct_name"], test_case["correct_name"],
4138 test_case["incorrect_name"]))
4139 all_problems.append(
4140 output_api.PresubmitPromptWarning(message, items=problems))
4141
4142 return all_problems
4143
4144
Dirk Pranke3c18a382019-03-15 01:07:514145def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
4146 # TODO(crbug.com/941824): We need to make sure the entries in
4147 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4148 # so that users of //buildtools in other projects get the same tooling
4149 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4150 # support to gclient, we can eliminate the duplication and delete
4151 # this presubmit check.
4152
4153 # Update this regexp if new revisions are added to the files.
4154 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264155 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514156
4157 # If a user is changing one revision, they need to change the same
4158 # line in both files. This means that any given change should contain
4159 # exactly the same list of changed lines that match the regexps. The
4160 # replace(' ', '') call allows us to ignore whitespace changes to the
4161 # lines. The 'long_text' parameter to the error will contain the
4162 # list of changed lines in both files, which should make it easy enough
4163 # to spot the error without going overboard in this implementation.
4164 revs_changes = {
4165 'DEPS': {},
4166 'buildtools/DEPS': {},
4167 }
4168 long_text = ''
4169
4170 for f in input_api.AffectedFiles(
4171 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4172 for line_num, line in f.ChangedContents():
4173 if rev_regexp.search(line):
4174 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4175 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4176
4177 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4178 return [output_api.PresubmitError(
4179 'Change buildtools revisions in sync in both //DEPS and '
4180 '//buildtools/DEPS.', long_text=long_text + '\n')]
4181 else:
4182 return []
4183
4184
Daniel Bratell93eb6c62019-04-29 20:13:364185def _CheckForTooLargeFiles(input_api, output_api):
4186 """Avoid large files, especially binary files, in the repository since
4187 git doesn't scale well for those. They will be in everyone's repo
4188 clones forever, forever making Chromium slower to clone and work
4189 with."""
4190
4191 # Uploading files to cloud storage is not trivial so we don't want
4192 # to set the limit too low, but the upper limit for "normal" large
4193 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4194 # anything over 20 MB is exceptional.
4195 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4196
4197 too_large_files = []
4198 for f in input_api.AffectedFiles():
4199 # Check both added and modified files (but not deleted files).
4200 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384201 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364202 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4203 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4204
4205 if too_large_files:
4206 message = (
4207 'Do not commit large files to git since git scales badly for those.\n' +
4208 'Instead put the large files in cloud storage and use DEPS to\n' +
4209 'fetch them.\n' + '\n'.join(too_large_files)
4210 )
4211 return [output_api.PresubmitError(
4212 'Too large files found in commit', long_text=message + '\n')]
4213 else:
4214 return []
4215
Max Morozb47503b2019-08-08 21:03:274216
4217def _CheckFuzzTargets(input_api, output_api):
4218 """Checks specific for fuzz target sources."""
4219 EXPORTED_SYMBOLS = [
4220 'LLVMFuzzerInitialize',
4221 'LLVMFuzzerCustomMutator',
4222 'LLVMFuzzerCustomCrossOver',
4223 'LLVMFuzzerMutate',
4224 ]
4225
4226 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4227
4228 def FilterFile(affected_file):
4229 """Ignore libFuzzer source code."""
4230 white_list = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4231 black_list = r"^third_party[\\/]libFuzzer"
4232
4233 return input_api.FilterSourceFile(
4234 affected_file,
4235 white_list=[white_list],
4236 black_list=[black_list])
4237
4238 files_with_missing_header = []
4239 for f in input_api.AffectedSourceFiles(FilterFile):
4240 contents = input_api.ReadFile(f, 'r')
4241 if REQUIRED_HEADER in contents:
4242 continue
4243
4244 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4245 files_with_missing_header.append(f.LocalPath())
4246
4247 if not files_with_missing_header:
4248 return []
4249
4250 long_text = (
4251 'If you define any of the libFuzzer optional functions (%s), it is '
4252 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4253 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4254 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4255 'to access command line arguments passed to the fuzzer. Instead, prefer '
4256 'static initialization and shared resources as documented in '
4257 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4258 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4259 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4260 )
4261
4262 return [output_api.PresubmitPromptWarning(
4263 message="Missing '%s' in:" % REQUIRED_HEADER,
4264 items=files_with_missing_header,
4265 long_text=long_text)]
4266
4267
Mohamed Heikald048240a2019-11-12 16:57:374268def _CheckNewImagesWarning(input_api, output_api):
4269 """
4270 Warns authors who add images into the repo to make sure their images are
4271 optimized before committing.
4272 """
4273 images_added = False
4274 image_paths = []
4275 errors = []
4276 filter_lambda = lambda x: input_api.FilterSourceFile(
4277 x,
4278 black_list=(('(?i).*test', r'.*\/junit\/')
4279 + input_api.DEFAULT_BLACK_LIST),
4280 white_list=[r'.*\/(drawable|mipmap)' ]
4281 )
4282 for f in input_api.AffectedFiles(
4283 include_deletes=False, file_filter=filter_lambda):
4284 local_path = f.LocalPath().lower()
4285 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4286 images_added = True
4287 image_paths.append(f)
4288 if images_added:
4289 errors.append(output_api.PresubmitPromptWarning(
4290 'It looks like you are trying to commit some images. If these are '
4291 'non-test-only images, please make sure to read and apply the tips in '
4292 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4293 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4294 'FYI only and will not block your CL on the CQ.', image_paths))
4295 return errors
4296
4297
dgnaa68d5e2015-06-10 10:08:224298def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574299 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224300 results = []
dgnaa68d5e2015-06-10 10:08:224301 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174302 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224303 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294304 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064305 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4306 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424307 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184308 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574309 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374310 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154311 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574312 return results
4313
4314def _AndroidSpecificOnCommitChecks(input_api, output_api):
4315 """Groups commit checks that target android code."""
4316 results = []
4317 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224318 return results
4319
Chris Hall59f8d0c72020-05-01 07:31:194320# TODO(chrishall): could we additionally match on any path owned by
4321# ui/accessibility/OWNERS ?
4322_ACCESSIBILITY_PATHS = (
4323 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4324 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4325 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4326 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4327 r"^content[\\/]browser[\\/]accessibility[\\/]",
4328 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4329 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4330 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4331 r"^ui[\\/]accessibility[\\/]",
4332 r"^ui[\\/]views[\\/]accessibility[\\/]",
4333)
4334
4335def _CheckAccessibilityRelnotesField(input_api, output_api):
4336 """Checks that commits to accessibility code contain an AX-Relnotes field in
4337 their commit message."""
4338 def FileFilter(affected_file):
4339 paths = _ACCESSIBILITY_PATHS
4340 return input_api.FilterSourceFile(affected_file, white_list=paths)
4341
4342 # Only consider changes affecting accessibility paths.
4343 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4344 return []
4345
Akihiro Ota08108e542020-05-20 15:30:534346 # AX-Relnotes can appear in either the description or the footer.
4347 # When searching the description, require 'AX-Relnotes:' to appear at the
4348 # beginning of a line.
4349 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4350 description_has_relnotes = any(ax_regex.match(line)
4351 for line in input_api.change.DescriptionText().lower().splitlines())
4352
4353 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4354 'AX-Relnotes', [])
4355 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194356 return []
4357
4358 # TODO(chrishall): link to Relnotes documentation in message.
4359 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4360 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4361 "user-facing changes"
4362 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4363 "user-facing effects"
4364 "\n if this is confusing or annoying then please contact members "
4365 "of ui/accessibility/OWNERS.")
4366
4367 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224368
[email protected]22c9bd72011-03-27 16:47:394369def _CommonChecks(input_api, output_api):
4370 """Checks common to both upload and commit."""
4371 results = []
4372 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384373 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544374 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084375
4376 author = input_api.change.author_email
4377 if author and author not in _KNOWN_ROBOTS:
4378 results.extend(
4379 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4380
Chris Hall59f8d0c72020-05-01 07:31:194381 results.extend(_CheckAccessibilityRelnotesField(input_api, output_api))
[email protected]55459852011-08-10 15:17:194382 results.extend(
[email protected]760deea2013-12-10 19:33:494383 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:234384 results.extend(
4385 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:544386 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:184387 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:344388 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:524389 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:224390 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:444391 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:594392 results.extend(_CheckNoBannedFunctions(input_api, output_api))
Mario Sanchez Prada2472cab2019-09-18 10:58:314393 results.extend(_CheckNoDeprecatedMojoTypes(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:064394 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:124395 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:184396 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:224397 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:304398 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:494399 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:034400 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:494401 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:444402 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
James Cook6b6597c2019-11-06 22:05:294403 results.extend(_CheckChromeOsSyncedPrefRegistration(input_api, output_api))
[email protected]d2530012013-01-25 16:39:274404 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:074405 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:544406 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:444407 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:394408 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:554409 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:044410 results.extend(
4411 input_api.canned_checks.CheckChangeHasNoTabs(
4412 input_api,
4413 output_api,
4414 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:404415 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:164416 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:084417 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:244418 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
[email protected]99171a92014-06-03 08:44:474419 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:044420 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:054421 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:144422 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:234423 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:434424 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:404425 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:154426 results.extend(_CheckJavaStyle(input_api, output_api))
Wez17c66962020-04-29 15:26:034427 results.extend(_CheckSecurityOwners(input_api, output_api))
Robert Sesek2c905332020-05-06 23:17:134428 results.extend(_CheckSecurityChanges(input_api, output_api))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264429 results.extend(_CheckSetNoParent(input_api, output_api))
jbriance9e12f162016-11-25 07:57:504430 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:364431 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:064432 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:134433 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:434434 results.extend(input_api.RunTests(
4435 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Rainhard Findlingfc31844c52020-05-15 09:58:264436 results.extend(_CheckStrings(input_api, output_api))
Mustafa Emre Acer51f2f742020-03-09 19:41:124437 results.extend(_CheckTranslationExpectations(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:024438 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:514439 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:364440 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Nate Fischerdfd9812e2019-07-18 22:03:004441 results.extend(_CheckPythonDevilInit(input_api, output_api))
Ken Rockotc31f4832020-05-29 18:58:514442 results.extend(_CheckStableMojomChanges(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244443
Vaclav Brozekcdc7defb2018-03-20 09:54:354444 for f in input_api.AffectedFiles():
4445 path, name = input_api.os_path.split(f.LocalPath())
4446 if name == 'PRESUBMIT.py':
4447 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004448 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4449 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074450 # The PRESUBMIT.py file (and the directory containing it) might
4451 # have been affected by being moved or removed, so only try to
4452 # run the tests if they still exist.
4453 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4454 input_api, output_api, full_path,
4455 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394456 return results
[email protected]1f7b4172010-01-28 01:17:344457
[email protected]b337cb5b2011-01-23 21:24:054458
[email protected]b8079ae4a2012-12-05 19:56:494459def _CheckPatchFiles(input_api, output_api):
4460 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4461 if f.LocalPath().endswith(('.orig', '.rej'))]
4462 if problems:
4463 return [output_api.PresubmitError(
4464 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034465 else:
4466 return []
[email protected]b8079ae4a2012-12-05 19:56:494467
4468
Kent Tamura5a8755d2017-06-29 23:37:074469def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214470 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4471 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4472 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074473 include_re = input_api.re.compile(
4474 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4475 extension_re = input_api.re.compile(r'\.[a-z]+$')
4476 errors = []
4477 for f in input_api.AffectedFiles():
4478 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4479 continue
4480 found_line_number = None
4481 found_macro = None
4482 for line_num, line in f.ChangedContents():
4483 match = macro_re.search(line)
4484 if match:
4485 found_line_number = line_num
4486 found_macro = match.group(2)
4487 break
4488 if not found_line_number:
4489 continue
4490
4491 found_include = False
4492 for line in f.NewContents():
4493 if include_re.search(line):
4494 found_include = True
4495 break
4496 if found_include:
4497 continue
4498
4499 if not f.LocalPath().endswith('.h'):
4500 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4501 try:
4502 content = input_api.ReadFile(primary_header_path, 'r')
4503 if include_re.search(content):
4504 continue
4505 except IOError:
4506 pass
4507 errors.append('%s:%d %s macro is used without including build/'
4508 'build_config.h.'
4509 % (f.LocalPath(), found_line_number, found_macro))
4510 if errors:
4511 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4512 return []
4513
4514
[email protected]b00342e7f2013-03-26 16:21:544515def _DidYouMeanOSMacro(bad_macro):
4516 try:
4517 return {'A': 'OS_ANDROID',
4518 'B': 'OS_BSD',
4519 'C': 'OS_CHROMEOS',
4520 'F': 'OS_FREEBSD',
4521 'L': 'OS_LINUX',
4522 'M': 'OS_MACOSX',
4523 'N': 'OS_NACL',
4524 'O': 'OS_OPENBSD',
4525 'P': 'OS_POSIX',
4526 'S': 'OS_SOLARIS',
4527 'W': 'OS_WIN'}[bad_macro[3].upper()]
4528 except KeyError:
4529 return ''
4530
4531
4532def _CheckForInvalidOSMacrosInFile(input_api, f):
4533 """Check for sensible looking, totally invalid OS macros."""
4534 preprocessor_statement = input_api.re.compile(r'^\s*#')
4535 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4536 results = []
4537 for lnum, line in f.ChangedContents():
4538 if preprocessor_statement.search(line):
4539 for match in os_macro.finditer(line):
4540 if not match.group(1) in _VALID_OS_MACROS:
4541 good = _DidYouMeanOSMacro(match.group(1))
4542 did_you_mean = ' (did you mean %s?)' % good if good else ''
4543 results.append(' %s:%d %s%s' % (f.LocalPath(),
4544 lnum,
4545 match.group(1),
4546 did_you_mean))
4547 return results
4548
4549
4550def _CheckForInvalidOSMacros(input_api, output_api):
4551 """Check all affected files for invalid OS macros."""
4552 bad_macros = []
tzik3f295992018-12-04 20:32:234553 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474554 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544555 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4556
4557 if not bad_macros:
4558 return []
4559
4560 return [output_api.PresubmitError(
4561 'Possibly invalid OS macro[s] found. Please fix your code\n'
4562 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4563
lliabraa35bab3932014-10-01 12:16:444564
4565def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4566 """Check all affected files for invalid "if defined" macros."""
4567 ALWAYS_DEFINED_MACROS = (
4568 "TARGET_CPU_PPC",
4569 "TARGET_CPU_PPC64",
4570 "TARGET_CPU_68K",
4571 "TARGET_CPU_X86",
4572 "TARGET_CPU_ARM",
4573 "TARGET_CPU_MIPS",
4574 "TARGET_CPU_SPARC",
4575 "TARGET_CPU_ALPHA",
4576 "TARGET_IPHONE_SIMULATOR",
4577 "TARGET_OS_EMBEDDED",
4578 "TARGET_OS_IPHONE",
4579 "TARGET_OS_MAC",
4580 "TARGET_OS_UNIX",
4581 "TARGET_OS_WIN32",
4582 )
4583 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4584 results = []
4585 for lnum, line in f.ChangedContents():
4586 for match in ifdef_macro.finditer(line):
4587 if match.group(1) in ALWAYS_DEFINED_MACROS:
4588 always_defined = ' %s is always defined. ' % match.group(1)
4589 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4590 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4591 lnum,
4592 always_defined,
4593 did_you_mean))
4594 return results
4595
4596
4597def _CheckForInvalidIfDefinedMacros(input_api, output_api):
4598 """Check all affected files for invalid "if defined" macros."""
4599 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054600 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444601 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054602 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214603 continue
lliabraa35bab3932014-10-01 12:16:444604 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4605 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4606
4607 if not bad_macros:
4608 return []
4609
4610 return [output_api.PresubmitError(
4611 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4612 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4613 bad_macros)]
4614
4615
mlamouria82272622014-09-16 18:45:044616def _CheckForIPCRules(input_api, output_api):
4617 """Check for same IPC rules described in
4618 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4619 """
4620 base_pattern = r'IPC_ENUM_TRAITS\('
4621 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4622 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4623
4624 problems = []
4625 for f in input_api.AffectedSourceFiles(None):
4626 local_path = f.LocalPath()
4627 if not local_path.endswith('.h'):
4628 continue
4629 for line_number, line in f.ChangedContents():
4630 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4631 problems.append(
4632 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4633
4634 if problems:
4635 return [output_api.PresubmitPromptWarning(
4636 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4637 else:
4638 return []
4639
[email protected]b00342e7f2013-03-26 16:21:544640
Stephen Martinis97a394142018-06-07 23:06:054641def _CheckForLongPathnames(input_api, output_api):
4642 """Check to make sure no files being submitted have long paths.
4643 This causes issues on Windows.
4644 """
4645 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194646 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054647 local_path = f.LocalPath()
4648 # Windows has a path limit of 260 characters. Limit path length to 200 so
4649 # that we have some extra for the prefix on dev machines and the bots.
4650 if len(local_path) > 200:
4651 problems.append(local_path)
4652
4653 if problems:
4654 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4655 else:
4656 return []
4657
4658
Daniel Bratell8ba52722018-03-02 16:06:144659def _CheckForIncludeGuards(input_api, output_api):
4660 """Check that header files have proper guards against multiple inclusion.
4661 If a file should not have such guards (and it probably should) then it
4662 should include the string "no-include-guard-because-multiply-included".
4663 """
Daniel Bratell6a75baef62018-06-04 10:04:454664 def is_chromium_header_file(f):
4665 # We only check header files under the control of the Chromium
4666 # project. That is, those outside third_party apart from
4667 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324668 # We also exclude *_message_generator.h headers as they use
4669 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454670 file_with_path = input_api.os_path.normpath(f.LocalPath())
4671 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324672 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454673 (not file_with_path.startswith('third_party') or
4674 file_with_path.startswith(
4675 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144676
4677 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344678 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144679
4680 errors = []
4681
Daniel Bratell6a75baef62018-06-04 10:04:454682 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144683 guard_name = None
4684 guard_line_number = None
4685 seen_guard_end = False
4686
4687 file_with_path = input_api.os_path.normpath(f.LocalPath())
4688 base_file_name = input_api.os_path.splitext(
4689 input_api.os_path.basename(file_with_path))[0]
4690 upper_base_file_name = base_file_name.upper()
4691
4692 expected_guard = replace_special_with_underscore(
4693 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144694
4695 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574696 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4697 # are too many (1000+) files with slight deviations from the
4698 # coding style. The most important part is that the include guard
4699 # is there, and that it's unique, not the name so this check is
4700 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144701 #
4702 # As code becomes more uniform, this could be made stricter.
4703
4704 guard_name_pattern_list = [
4705 # Anything with the right suffix (maybe with an extra _).
4706 r'\w+_H__?',
4707
Daniel Bratell39b5b062018-05-16 18:09:574708 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144709 r'\w+_h',
4710
4711 # Anything including the uppercase name of the file.
4712 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4713 upper_base_file_name)) + r'\w*',
4714 ]
4715 guard_name_pattern = '|'.join(guard_name_pattern_list)
4716 guard_pattern = input_api.re.compile(
4717 r'#ifndef\s+(' + guard_name_pattern + ')')
4718
4719 for line_number, line in enumerate(f.NewContents()):
4720 if 'no-include-guard-because-multiply-included' in line:
4721 guard_name = 'DUMMY' # To not trigger check outside the loop.
4722 break
4723
4724 if guard_name is None:
4725 match = guard_pattern.match(line)
4726 if match:
4727 guard_name = match.group(1)
4728 guard_line_number = line_number
4729
Daniel Bratell39b5b062018-05-16 18:09:574730 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454731 # don't match the chromium style guide, but new files should
4732 # get it right.
4733 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574734 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144735 errors.append(output_api.PresubmitPromptWarning(
4736 'Header using the wrong include guard name %s' % guard_name,
4737 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574738 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144739 else:
4740 # The line after #ifndef should have a #define of the same name.
4741 if line_number == guard_line_number + 1:
4742 expected_line = '#define %s' % guard_name
4743 if line != expected_line:
4744 errors.append(output_api.PresubmitPromptWarning(
4745 'Missing "%s" for include guard' % expected_line,
4746 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4747 'Expected: %r\nGot: %r' % (expected_line, line)))
4748
4749 if not seen_guard_end and line == '#endif // %s' % guard_name:
4750 seen_guard_end = True
4751 elif seen_guard_end:
4752 if line.strip() != '':
4753 errors.append(output_api.PresubmitPromptWarning(
4754 'Include guard %s not covering the whole file' % (
4755 guard_name), [f.LocalPath()]))
4756 break # Nothing else to check and enough to warn once.
4757
4758 if guard_name is None:
4759 errors.append(output_api.PresubmitPromptWarning(
4760 'Missing include guard %s' % expected_guard,
4761 [f.LocalPath()],
4762 'Missing include guard in %s\n'
4763 'Recommended name: %s\n'
4764 'This check can be disabled by having the string\n'
4765 'no-include-guard-because-multiply-included in the header.' %
4766 (f.LocalPath(), expected_guard)))
4767
4768 return errors
4769
4770
mostynbb639aca52015-01-07 20:31:234771def _CheckForWindowsLineEndings(input_api, output_api):
4772 """Check source code and known ascii text files for Windows style line
4773 endings.
4774 """
earthdok1b5e0ee2015-03-10 15:19:104775 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234776
4777 file_inclusion_pattern = (
4778 known_text_files,
4779 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4780 )
4781
mostynbb639aca52015-01-07 20:31:234782 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534783 source_file_filter = lambda f: input_api.FilterSourceFile(
4784 f, white_list=file_inclusion_pattern, black_list=None)
4785 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504786 include_file = False
4787 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234788 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504789 include_file = True
4790 if include_file:
4791 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234792
4793 if problems:
4794 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4795 'these files to contain Windows style line endings?\n' +
4796 '\n'.join(problems))]
4797
4798 return []
4799
4800
Vaclav Brozekd5de76a2018-03-17 07:57:504801def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134802 """Checks that all source files use SYSLOG properly."""
4803 syslog_files = []
4804 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564805 for line_number, line in f.ChangedContents():
4806 if 'SYSLOG' in line:
4807 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4808
pastarmovj89f7ee12016-09-20 14:58:134809 if syslog_files:
4810 return [output_api.PresubmitPromptWarning(
4811 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4812 ' calls.\nFiles to check:\n', items=syslog_files)]
4813 return []
4814
4815
[email protected]1f7b4172010-01-28 01:17:344816def CheckChangeOnUpload(input_api, output_api):
4817 results = []
4818 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:474819 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:284820 results.extend(
jam93a6ee792017-02-08 23:59:224821 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:194822 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:224823 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:134824 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:164825 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:534826 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194827 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Max Morozb47503b2019-08-08 21:03:274828 results.extend(_CheckFuzzTargets(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544829 return results
[email protected]ca8d1982009-02-19 16:33:124830
4831
[email protected]1bfb8322014-04-23 01:02:414832def GetTryServerMasterForBot(bot):
4833 """Returns the Try Server master for the given bot.
4834
[email protected]0bb112362014-07-26 04:38:324835 It tries to guess the master from the bot name, but may still fail
4836 and return None. There is no longer a default master.
4837 """
4838 # Potentially ambiguous bot names are listed explicitly.
4839 master_map = {
tandriie5587792016-07-14 00:34:504840 'chromium_presubmit': 'master.tryserver.chromium.linux',
4841 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414842 }
[email protected]0bb112362014-07-26 04:38:324843 master = master_map.get(bot)
4844 if not master:
wnwen4fbaab82016-05-25 12:54:364845 if 'android' in bot:
tandriie5587792016-07-14 00:34:504846 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364847 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504848 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324849 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504850 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324851 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504852 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324853 return master
[email protected]1bfb8322014-04-23 01:02:414854
4855
[email protected]ca8d1982009-02-19 16:33:124856def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:544857 results = []
[email protected]1f7b4172010-01-28 01:17:344858 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574859 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544860 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274861 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344862 input_api,
4863 output_api,
[email protected]2fdd1f362013-01-16 03:56:034864 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274865
jam93a6ee792017-02-08 23:59:224866 results.extend(
4867 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544868 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4869 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384870 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4871 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414872 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4873 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544874 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144875
4876
Rainhard Findlingfc31844c52020-05-15 09:58:264877def _CheckStrings(input_api, output_api):
4878 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024879 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4880 # footer is set to true.
4881 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264882 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024883 footer.lower()
4884 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264885 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024886
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144887 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264888 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144889 import sys
4890 from io import StringIO
4891
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144892 new_or_added_paths = set(f.LocalPath()
4893 for f in input_api.AffectedFiles()
4894 if (f.Action() == 'A' or f.Action() == 'M'))
4895 removed_paths = set(f.LocalPath()
4896 for f in input_api.AffectedFiles(include_deletes=True)
4897 if f.Action() == 'D')
4898
4899 affected_grds = [f for f in input_api.AffectedFiles()
Rainhard Findlingfc31844c52020-05-15 09:58:264900 if (f.LocalPath().endswith(('.grd', '.grdp')))]
meacer8c0d3832019-12-26 21:46:164901 if not affected_grds:
4902 return []
4903
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144904 affected_png_paths = [f.AbsoluteLocalPath()
4905 for f in input_api.AffectedFiles()
4906 if (f.LocalPath().endswith('.png'))]
4907
4908 # Check for screenshots. Developers can upload screenshots using
4909 # tools/translation/upload_screenshots.py which finds and uploads
4910 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4911 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4912 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4913 #
4914 # The logic here is as follows:
4915 #
4916 # - If the CL has a .png file under the screenshots directory for a grd
4917 # file, warn the developer. Actual images should never be checked into the
4918 # Chrome repo.
4919 #
4920 # - If the CL contains modified or new messages in grd files and doesn't
4921 # contain the corresponding .sha1 files, warn the developer to add images
4922 # and upload them via tools/translation/upload_screenshots.py.
4923 #
4924 # - If the CL contains modified or new messages in grd files and the
4925 # corresponding .sha1 files, everything looks good.
4926 #
4927 # - If the CL contains removed messages in grd files but the corresponding
4928 # .sha1 files aren't removed, warn the developer to remove them.
4929 unnecessary_screenshots = []
4930 missing_sha1 = []
4931 unnecessary_sha1_files = []
4932
Rainhard Findlingfc31844c52020-05-15 09:58:264933 # This checks verifies that the ICU syntax of messages this CL touched is
4934 # valid, and reports any found syntax errors.
4935 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4936 # without developers being aware of them. Later on, such ICU syntax errors
4937 # break message extraction for translation, hence would block Chromium
4938 # translations until they are fixed.
4939 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144940
4941 def _CheckScreenshotAdded(screenshots_dir, message_id):
4942 sha1_path = input_api.os_path.join(
4943 screenshots_dir, message_id + '.png.sha1')
4944 if sha1_path not in new_or_added_paths:
4945 missing_sha1.append(sha1_path)
4946
4947
4948 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4949 sha1_path = input_api.os_path.join(
4950 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034951 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144952 unnecessary_sha1_files.append(sha1_path)
4953
Rainhard Findlingfc31844c52020-05-15 09:58:264954
4955 def _ValidateIcuSyntax(text, level, signatures):
4956 """Validates ICU syntax of a text string.
4957
4958 Check if text looks similar to ICU and checks for ICU syntax correctness
4959 in this case. Reports various issues with ICU syntax and values of
4960 variants. Supports checking of nested messages. Accumulate information of
4961 each ICU messages found in the text for further checking.
4962
4963 Args:
4964 text: a string to check.
4965 level: a number of current nesting level.
4966 signatures: an accumulator, a list of tuple of (level, variable,
4967 kind, variants).
4968
4969 Returns:
4970 None if a string is not ICU or no issue detected.
4971 A tuple of (message, start index, end index) if an issue detected.
4972 """
4973 valid_types = {
4974 'plural': (frozenset(
4975 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4976 frozenset(['=1', 'other'])),
4977 'selectordinal': (frozenset(
4978 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4979 frozenset(['one', 'other'])),
4980 'select': (frozenset(), frozenset(['other'])),
4981 }
4982
4983 # Check if the message looks like an attempt to use ICU
4984 # plural. If yes - check if its syntax strictly matches ICU format.
4985 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4986 if not like:
4987 signatures.append((level, None, None, None))
4988 return
4989
4990 # Check for valid prefix and suffix
4991 m = re.match(
4992 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4993 r'(plural|selectordinal|select),\s*'
4994 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4995 if not m:
4996 return (('This message looks like an ICU plural, '
4997 'but does not follow ICU syntax.'), like.start(), like.end())
4998 starting, variable, kind, variant_pairs = m.groups()
4999 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5000 if depth:
5001 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5002 len(text))
5003 first = text[0]
5004 ending = text[last_pos:]
5005 if not starting:
5006 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5007 last_pos)
5008 if not ending or '}' not in ending:
5009 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5010 last_pos)
5011 elif first != '{':
5012 return (
5013 ('Invalid ICU format. Extra characters at the start of a complex '
5014 'message (go/icu-message-migration): "%s"') %
5015 starting, 0, len(starting))
5016 elif ending != '}':
5017 return (('Invalid ICU format. Extra characters at the end of a complex '
5018 'message (go/icu-message-migration): "%s"')
5019 % ending, last_pos - 1, len(text) - 1)
5020 if kind not in valid_types:
5021 return (('Unknown ICU message type %s. '
5022 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5023 known, required = valid_types[kind]
5024 defined_variants = set()
5025 for variant, variant_range, value, value_range in variants:
5026 start, end = variant_range
5027 if variant in defined_variants:
5028 return ('Variant "%s" is defined more than once' % variant,
5029 start, end)
5030 elif known and variant not in known:
5031 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5032 start, end)
5033 defined_variants.add(variant)
5034 # Check for nested structure
5035 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5036 if res:
5037 return (res[0], res[1] + value_range[0] + 1,
5038 res[2] + value_range[0] + 1)
5039 missing = required - defined_variants
5040 if missing:
5041 return ('Required variants missing: %s' % ', '.join(missing), 0,
5042 len(text))
5043 signatures.append((level, variable, kind, defined_variants))
5044
5045
5046 def _ParseIcuVariants(text, offset=0):
5047 """Parse variants part of ICU complex message.
5048
5049 Builds a tuple of variant names and values, as well as
5050 their offsets in the input string.
5051
5052 Args:
5053 text: a string to parse
5054 offset: additional offset to add to positions in the text to get correct
5055 position in the complete ICU string.
5056
5057 Returns:
5058 List of tuples, each tuple consist of four fields: variant name,
5059 variant name span (tuple of two integers), variant value, value
5060 span (tuple of two integers).
5061 """
5062 depth, start, end = 0, -1, -1
5063 variants = []
5064 key = None
5065 for idx, char in enumerate(text):
5066 if char == '{':
5067 if not depth:
5068 start = idx
5069 chunk = text[end + 1:start]
5070 key = chunk.strip()
5071 pos = offset + end + 1 + chunk.find(key)
5072 span = (pos, pos + len(key))
5073 depth += 1
5074 elif char == '}':
5075 if not depth:
5076 return variants, depth, offset + idx
5077 depth -= 1
5078 if not depth:
5079 end = idx
5080 variants.append((key, span, text[start:end + 1], (offset + start,
5081 offset + end + 1)))
5082 return variants, depth, offset + end + 1
5083
meacer8c0d3832019-12-26 21:46:165084 try:
5085 old_sys_path = sys.path
5086 sys.path = sys.path + [input_api.os_path.join(
5087 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5088 from helper import grd_helper
5089 finally:
5090 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145091
5092 for f in affected_grds:
5093 file_path = f.LocalPath()
5094 old_id_to_msg_map = {}
5095 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385096 # Note that this code doesn't check if the file has been deleted. This is
5097 # OK because it only uses the old and new file contents and doesn't load
5098 # the file via its path.
5099 # It's also possible that a file's content refers to a renamed or deleted
5100 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5101 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5102 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145103 if file_path.endswith('.grdp'):
5104 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585105 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395106 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145107 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585108 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395109 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110 else:
meacerff8a9b62019-12-10 19:43:585111 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145112 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585113 old_id_to_msg_map = grd_helper.GetGrdMessages(
5114 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145115 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585116 new_id_to_msg_map = grd_helper.GetGrdMessages(
5117 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
5119 # Compute added, removed and modified message IDs.
5120 old_ids = set(old_id_to_msg_map)
5121 new_ids = set(new_id_to_msg_map)
5122 added_ids = new_ids - old_ids
5123 removed_ids = old_ids - new_ids
5124 modified_ids = set([])
5125 for key in old_ids.intersection(new_ids):
5126 if (old_id_to_msg_map[key].FormatXml()
5127 != new_id_to_msg_map[key].FormatXml()):
5128 modified_ids.add(key)
5129
5130 grd_name, ext = input_api.os_path.splitext(
5131 input_api.os_path.basename(file_path))
5132 screenshots_dir = input_api.os_path.join(
5133 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5134
Rainhard Findlingfc31844c52020-05-15 09:58:265135 if run_screenshot_check:
5136 # Check the screenshot directory for .png files. Warn if there is any.
5137 for png_path in affected_png_paths:
5138 if png_path.startswith(screenshots_dir):
5139 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
Rainhard Findlingfc31844c52020-05-15 09:58:265141 for added_id in added_ids:
5142 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145143
Rainhard Findlingfc31844c52020-05-15 09:58:265144 for modified_id in modified_ids:
5145 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145146
Rainhard Findlingfc31844c52020-05-15 09:58:265147 for removed_id in removed_ids:
5148 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5149
5150 # Check new and changed strings for ICU syntax errors.
5151 for key in added_ids.union(modified_ids):
5152 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5153 err = _ValidateIcuSyntax(msg, 0, [])
5154 if err is not None:
5155 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145156
5157 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265158 if run_screenshot_check:
5159 if unnecessary_screenshots:
5160 results.append(output_api.PresubmitNotifyResult(
5161 'Do not include actual screenshots in the changelist. Run '
5162 'tools/translate/upload_screenshots.py to upload them instead:',
5163 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
Rainhard Findlingfc31844c52020-05-15 09:58:265165 if missing_sha1:
5166 results.append(output_api.PresubmitNotifyResult(
5167 'You are adding or modifying UI strings.\n'
5168 'To ensure the best translations, take screenshots of the relevant UI '
5169 '(https://g.co/chrome/translation) and add these files to your '
5170 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145171
Rainhard Findlingfc31844c52020-05-15 09:58:265172 if unnecessary_sha1_files:
5173 results.append(output_api.PresubmitNotifyResult(
5174 'You removed strings associated with these files. Remove:',
5175 sorted(unnecessary_sha1_files)))
5176 else:
5177 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5178 'screenshots check.'))
5179
5180 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075181 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265182 'ICU syntax errors were found in the following strings (problems or '
5183 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145184
5185 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125186
5187
5188def _CheckTranslationExpectations(input_api, output_api,
5189 repo_root=None,
5190 translation_expectations_path=None,
5191 grd_files=None):
5192 import sys
5193 affected_grds = [f for f in input_api.AffectedFiles()
5194 if (f.LocalPath().endswith('.grd') or
5195 f.LocalPath().endswith('.grdp'))]
5196 if not affected_grds:
5197 return []
5198
5199 try:
5200 old_sys_path = sys.path
5201 sys.path = sys.path + [
5202 input_api.os_path.join(
5203 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5204 from helper import git_helper
5205 from helper import translation_helper
5206 finally:
5207 sys.path = old_sys_path
5208
5209 # Check that translation expectations can be parsed and we can get a list of
5210 # translatable grd files. |repo_root| and |translation_expectations_path| are
5211 # only passed by tests.
5212 if not repo_root:
5213 repo_root = input_api.PresubmitLocalPath()
5214 if not translation_expectations_path:
5215 translation_expectations_path = input_api.os_path.join(
5216 repo_root, 'tools', 'gritsettings',
5217 'translation_expectations.pyl')
5218 if not grd_files:
5219 grd_files = git_helper.list_grds_in_repository(repo_root)
5220
5221 try:
5222 translation_helper.get_translatable_grds(repo_root, grd_files,
5223 translation_expectations_path)
5224 except Exception as e:
5225 return [output_api.PresubmitNotifyResult(
5226 'Failed to get a list of translatable grd files. This happens when:\n'
5227 ' - One of the modified grd or grdp files cannot be parsed or\n'
5228 ' - %s is not updated.\n'
5229 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5230 return []
Ken Rockotc31f4832020-05-29 18:58:515231
5232
5233def _CheckStableMojomChanges(input_api, output_api):
5234 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095235 changed_mojoms = input_api.AffectedFiles(
5236 include_deletes=True,
5237 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515238 delta = []
5239 for mojom in changed_mojoms:
5240 old_contents = ''.join(mojom.OldContents()) or None
5241 new_contents = ''.join(mojom.NewContents()) or None
5242 delta.append({
5243 'filename': mojom.LocalPath(),
5244 'old': '\n'.join(mojom.OldContents()) or None,
5245 'new': '\n'.join(mojom.NewContents()) or None,
5246 })
5247
5248 process = input_api.subprocess.Popen(
5249 [input_api.python_executable,
5250 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5251 'public', 'tools', 'mojom',
5252 'check_stable_mojom_compatibility.py'),
5253 '--src-root', input_api.PresubmitLocalPath()],
5254 stdin=input_api.subprocess.PIPE,
5255 stdout=input_api.subprocess.PIPE,
5256 stderr=input_api.subprocess.PIPE,
5257 universal_newlines=True)
5258 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5259 if process.returncode:
5260 return [output_api.PresubmitError(
5261 'One or more [Stable] mojom definitions appears to have been changed '
5262 'in a way that is not backward-compatible.',
5263 long_text=error)]
5264 return []