blob: b3133c9764b64c4faa14cd088ed3c9032f696872 [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"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
John Abd-El-Malek759fea62021-03-13 03:41:1438_EXCLUDED_SET_NO_PARENT_PATHS = (
39 # It's for historical reasons that blink isn't a top level directory, where
40 # it would be allowed to have "set noparent" to avoid top level owners
41 # accidentally +1ing changes.
42 'third_party/blink/OWNERS',
43)
44
wnwenbdc444e2016-05-25 13:44:1545
[email protected]06e6d0ff2012-12-11 01:36:4446# Fragment of a regular expression that matches C++ and Objective-C++
47# implementation files.
48_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
49
wnwenbdc444e2016-05-25 13:44:1550
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1951# Fragment of a regular expression that matches C++ and Objective-C++
52# header files.
53_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
54
55
[email protected]06e6d0ff2012-12-11 01:36:4456# Regular expression that matches code only used for test binaries
57# (best effort).
58_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0459 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4460 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1361 # Test suite files, like:
62 # foo_browsertest.cc
63 # bar_unittest_mac.cc (suffix)
64 # baz_unittests.cc (plural)
65 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1266 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1867 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4468 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0469 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4370 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0471 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4372 # Web test harness.
73 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4774 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0475 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0876 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0477 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4178 # EarlGrey app side code for tests.
79 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1780 # Views Examples code
81 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4182 # Chromium Codelab
83 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4484)
[email protected]ca8d1982009-02-19 16:33:1285
Daniel Bratell609102be2019-03-27 20:53:2186_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1587
[email protected]eea609a2011-11-18 13:10:1288_TEST_ONLY_WARNING = (
89 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5590 'production code. If you are doing this from inside another method\n'
91 'named as *ForTesting(), then consider exposing things to have tests\n'
92 'make that same call directly.\n'
93 'If that is not possible, you may put a comment on the same line with\n'
94 ' // IN-TEST \n'
95 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
96 'method and can be ignored. Do not do this inside production code.\n'
97 'The android-binary-size trybot will block if the method exists in the\n'
98 'release apk.')
[email protected]eea609a2011-11-18 13:10:1299
100
[email protected]cf9b78f2012-11-14 11:40:28101_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:40102 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:21103 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
104 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:28105
Michael Thiessen44457642020-02-06 00:24:15106# Format: Sequence of tuples containing:
107# * Full import path.
108# * Sequence of strings to show when the pattern matches.
109# * Sequence of path or filename exceptions to this rule
110_BANNED_JAVA_IMPORTS = (
111 (
Colin Blundell170d78c82020-03-12 13:56:04112 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15113 (
114 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
115 ),
116 (
117 'net/android/javatests/src/org/chromium/net/'
118 'AndroidProxySelectorTest.java',
119 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04120 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15121 ),
122 ),
Michael Thiessened631912020-08-07 19:01:31123 (
124 'android.support.test.rule.UiThreadTestRule;',
125 (
126 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43127 '@org.chromium.base.test.UiThreadTest on test methods that should run '
128 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31129 ),
130 (),
131 ),
132 (
133 'android.support.test.annotation.UiThreadTest;',
134 (
135 'Do not use android.support.test.annotation.UiThreadTest, use '
136 'org.chromium.base.test.UiThreadTest instead. See '
137 'https://crbug.com/1111893.',
138 ),
139 ()
Michael Thiessenfd6919b2020-12-08 20:44:01140 ),
141 (
142 'android.support.test.rule.ActivityTestRule;',
143 (
144 'Do not use ActivityTestRule, use '
145 'org.chromium.base.test.BaseActivityTestRule instead.',
146 ),
147 (
148 'components/cronet/',
149 )
Michael Thiessened631912020-08-07 19:01:31150 )
Michael Thiessen44457642020-02-06 00:24:15151)
wnwenbdc444e2016-05-25 13:44:15152
Daniel Bratell609102be2019-03-27 20:53:21153# Format: Sequence of tuples containing:
154# * String pattern or, if starting with a slash, a regular expression.
155# * Sequence of strings to show when the pattern matches.
156# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41157_BANNED_JAVA_FUNCTIONS = (
158 (
159 'StrictMode.allowThreadDiskReads()',
160 (
161 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
162 'directly.',
163 ),
164 False,
165 ),
166 (
167 'StrictMode.allowThreadDiskWrites()',
168 (
169 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
170 'directly.',
171 ),
172 False,
173 ),
Michael Thiessen0f2547e2020-07-27 21:55:36174 (
175 '.waitForIdleSync()',
176 (
177 'Do not use waitForIdleSync as it masks underlying issues. There is '
178 'almost always something else you should wait on instead.',
179 ),
180 False,
181 ),
Eric Stevensona9a980972017-09-23 00:04:41182)
183
Daniel Bratell609102be2019-03-27 20:53:21184# Format: Sequence of tuples containing:
185# * String pattern or, if starting with a slash, a regular expression.
186# * Sequence of strings to show when the pattern matches.
187# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59188_BANNED_OBJC_FUNCTIONS = (
189 (
190 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20191 (
192 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59193 'prohibited. Please use CrTrackingArea instead.',
194 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
195 ),
196 False,
197 ),
198 (
[email protected]eaae1972014-04-16 04:17:26199 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20200 (
201 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59202 'instead.',
203 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
204 ),
205 False,
206 ),
207 (
208 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20209 (
210 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59211 'Please use |convertPoint:(point) fromView:nil| instead.',
212 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
213 ),
214 True,
215 ),
216 (
217 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20218 (
219 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59220 'Please use |convertPoint:(point) toView:nil| instead.',
221 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
222 ),
223 True,
224 ),
225 (
226 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20227 (
228 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59229 'Please use |convertRect:(point) fromView:nil| instead.',
230 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
231 ),
232 True,
233 ),
234 (
235 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20236 (
237 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59238 'Please use |convertRect:(point) toView:nil| instead.',
239 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
240 ),
241 True,
242 ),
243 (
244 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20245 (
246 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59247 'Please use |convertSize:(point) fromView:nil| instead.',
248 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
249 ),
250 True,
251 ),
252 (
253 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20254 (
255 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59256 'Please use |convertSize:(point) toView:nil| instead.',
257 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
258 ),
259 True,
260 ),
jif65398702016-10-27 10:19:48261 (
262 r"/\s+UTF8String\s*]",
263 (
264 'The use of -[NSString UTF8String] is dangerous as it can return null',
265 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
266 'Please use |SysNSStringToUTF8| instead.',
267 ),
268 True,
269 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34270 (
271 r'__unsafe_unretained',
272 (
273 'The use of __unsafe_unretained is almost certainly wrong, unless',
274 'when interacting with NSFastEnumeration or NSInvocation.',
275 'Please use __weak in files build with ARC, nothing otherwise.',
276 ),
277 False,
278 ),
Avi Drissman7382afa02019-04-29 23:27:13279 (
280 'freeWhenDone:NO',
281 (
282 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
283 'Foundation types is prohibited.',
284 ),
285 True,
286 ),
[email protected]127f18ec2012-06-16 05:05:59287)
288
Daniel Bratell609102be2019-03-27 20:53:21289# Format: Sequence of tuples containing:
290# * String pattern or, if starting with a slash, a regular expression.
291# * Sequence of strings to show when the pattern matches.
292# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54293_BANNED_IOS_OBJC_FUNCTIONS = (
294 (
295 r'/\bTEST[(]',
296 (
297 'TEST() macro should not be used in Objective-C++ code as it does not ',
298 'drain the autorelease pool at the end of the test. Use TEST_F() ',
299 'macro instead with a fixture inheriting from PlatformTest (or a ',
300 'typedef).'
301 ),
302 True,
303 ),
304 (
305 r'/\btesting::Test\b',
306 (
307 'testing::Test should not be used in Objective-C++ code as it does ',
308 'not drain the autorelease pool at the end of the test. Use ',
309 'PlatformTest instead.'
310 ),
311 True,
312 ),
313)
314
Peter K. Lee6c03ccff2019-07-15 14:40:05315# Format: Sequence of tuples containing:
316# * String pattern or, if starting with a slash, a regular expression.
317# * Sequence of strings to show when the pattern matches.
318# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
319_BANNED_IOS_EGTEST_FUNCTIONS = (
320 (
321 r'/\bEXPECT_OCMOCK_VERIFY\b',
322 (
323 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
324 'it is meant for GTests. Use [mock verify] instead.'
325 ),
326 True,
327 ),
328)
329
danakj7a2b7082019-05-21 21:13:51330# Directories that contain deprecated Bind() or Callback types.
331# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36332# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51333# echo "-- $i"
Alexander Cooperd1244c582021-01-26 02:25:27334# (cd $i; git grep -nP \
335# 'base::(Bind\(|(Cancelable)?(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51336# done
337#
338# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
339# when they have been converted to modern callback types (OnceCallback,
340# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
341# checks for them and prevent regressions.
342_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51343 '^base/callback.h', # Intentional.
Alex Turnerb3ea38c2020-11-25 18:03:07344 '^base/cancelable_callback.h', # Intentional.
Alexander Cooperb3f1af662021-02-01 19:47:26345 "^chrome/browser/ash/accessibility/",
Alexander Cooperb3f1af662021-02-01 19:47:26346 "^chrome/browser/metrics/",
Alexander Cooperb3f1af662021-02-01 19:47:26347 "^chrome/browser/prefetch/no_state_prefetch/",
348 '^chrome/browser/previews/',
Alexander Cooper6b447b22020-07-22 00:47:18349 '^chrome/browser/resources/chromeos/accessibility/',
Alexander Cooper6b447b22020-07-22 00:47:18350 '^chrome/browser/sync_file_system/',
Alexander Cooperb3f1af662021-02-01 19:47:26351 "^components/browsing_data/content/",
Alexander Cooperb3f1af662021-02-01 19:47:26352 "^components/feature_engagement/internal/",
353 "^docs/callback\\.md", # Intentional
354 "^docs/webui_explainer\\.md",
355 "^docs/process/lsc/large_scale_changes\\.md", # Intentional
356 "^docs/security/mojo\\.md",
357 "^docs/threading_and_tasks\\.md",
358 "^docs/ui/learn/bestpractices/layout\\.md",
Alan Cutter04a00642020-03-02 01:45:20359 '^extensions/browser/',
360 '^extensions/renderer/',
Alexander Cooperb3f1af662021-02-01 19:47:26361 '^third_party/blink/PRESUBMIT_test.py', # Intentional.
362 '^third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py' # Intentional pylint: disable=line-too-long
danakj7a2b7082019-05-21 21:13:51363 '^tools/clang/base_bind_rewriters/', # Intentional.
364 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51365))
[email protected]127f18ec2012-06-16 05:05:59366
Daniel Bratell609102be2019-03-27 20:53:21367# Format: Sequence of tuples containing:
368# * String pattern or, if starting with a slash, a regular expression.
369# * Sequence of strings to show when the pattern matches.
370# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
371# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59372_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20373 (
Peter Kasting94a56c42019-10-25 21:54:04374 r'/\busing namespace ',
375 (
376 'Using directives ("using namespace x") are banned by the Google Style',
377 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
378 'Explicitly qualify symbols or use using declarations ("using x::foo").',
379 ),
380 True,
381 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
382 ),
Antonio Gomes07300d02019-03-13 20:59:57383 # Make sure that gtest's FRIEND_TEST() macro is not used; the
384 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
385 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53386 (
[email protected]23e6cbc2012-06-16 18:51:20387 'FRIEND_TEST(',
388 (
[email protected]e3c945502012-06-26 20:01:49389 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20390 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
391 ),
392 False,
[email protected]7345da02012-11-27 14:31:49393 (),
[email protected]23e6cbc2012-06-16 18:51:20394 ),
395 (
tomhudsone2c14d552016-05-26 17:07:46396 'setMatrixClip',
397 (
398 'Overriding setMatrixClip() is prohibited; ',
399 'the base function is deprecated. ',
400 ),
401 True,
402 (),
403 ),
404 (
[email protected]52657f62013-05-20 05:30:31405 'SkRefPtr',
406 (
407 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22408 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31409 ),
410 True,
411 (),
412 ),
413 (
414 'SkAutoRef',
415 (
416 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22417 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31418 ),
419 True,
420 (),
421 ),
422 (
423 'SkAutoTUnref',
424 (
425 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22426 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31427 ),
428 True,
429 (),
430 ),
431 (
432 'SkAutoUnref',
433 (
434 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
435 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22436 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31437 ),
438 True,
439 (),
440 ),
[email protected]d89eec82013-12-03 14:10:59441 (
442 r'/HANDLE_EINTR\(.*close',
443 (
444 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
445 'descriptor will be closed, and it is incorrect to retry the close.',
446 'Either call close directly and ignore its return value, or wrap close',
447 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
448 ),
449 True,
450 (),
451 ),
452 (
453 r'/IGNORE_EINTR\((?!.*close)',
454 (
455 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
456 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
457 ),
458 True,
459 (
460 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04461 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
462 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59463 ),
464 ),
[email protected]ec5b3f02014-04-04 18:43:43465 (
466 r'/v8::Extension\(',
467 (
468 'Do not introduce new v8::Extensions into the code base, use',
469 'gin::Wrappable instead. See http://crbug.com/334679',
470 ),
471 True,
[email protected]f55c90ee62014-04-12 00:50:03472 (
Egor Paskoce145c42018-09-28 19:31:04473 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03474 ),
[email protected]ec5b3f02014-04-04 18:43:43475 ),
skyostilf9469f72015-04-20 10:38:52476 (
jame2d1a952016-04-02 00:27:10477 '#pragma comment(lib,',
478 (
479 'Specify libraries to link with in build files and not in the source.',
480 ),
481 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41482 (
tzik3f295992018-12-04 20:32:23483 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04484 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41485 ),
jame2d1a952016-04-02 00:27:10486 ),
fdorayc4ac18d2017-05-01 21:39:59487 (
Gabriel Charette7cc6c432018-04-25 20:52:02488 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59489 (
490 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
491 ),
492 False,
493 (),
494 ),
495 (
Gabriel Charette7cc6c432018-04-25 20:52:02496 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59497 (
498 'Consider using THREAD_CHECKER macros instead of the class directly.',
499 ),
500 False,
501 (),
502 ),
dbeamb6f4fde2017-06-15 04:03:06503 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06504 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
505 (
506 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
507 'deprecated (http://crbug.com/634507). Please avoid converting away',
508 'from the Time types in Chromium code, especially if any math is',
509 'being done on time values. For interfacing with platform/library',
510 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
511 'type converter methods instead. For faking TimeXXX values (for unit',
512 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
513 'other use cases, please contact base/time/OWNERS.',
514 ),
515 False,
516 (),
517 ),
518 (
dbeamb6f4fde2017-06-15 04:03:06519 'CallJavascriptFunctionUnsafe',
520 (
521 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
522 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
523 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
524 ),
525 False,
526 (
Egor Paskoce145c42018-09-28 19:31:04527 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
528 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
529 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06530 ),
531 ),
dskiba1474c2bfd62017-07-20 02:19:24532 (
533 'leveldb::DB::Open',
534 (
535 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
536 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
537 "Chrome's tracing, making their memory usage visible.",
538 ),
539 True,
540 (
541 r'^third_party/leveldatabase/.*\.(cc|h)$',
542 ),
Gabriel Charette0592c3a2017-07-26 12:02:04543 ),
544 (
Chris Mumfordc38afb62017-10-09 17:55:08545 'leveldb::NewMemEnv',
546 (
547 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58548 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
549 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08550 ),
551 True,
552 (
553 r'^third_party/leveldatabase/.*\.(cc|h)$',
554 ),
555 ),
556 (
Gabriel Charetted9839bc2017-07-29 14:17:47557 'RunLoop::QuitCurrent',
558 (
Robert Liao64b7ab22017-08-04 23:03:43559 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
560 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47561 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41562 False,
Gabriel Charetted9839bc2017-07-29 14:17:47563 (),
Gabriel Charettea44975052017-08-21 23:14:04564 ),
565 (
566 'base::ScopedMockTimeMessageLoopTaskRunner',
567 (
Gabriel Charette87cc1af2018-04-25 20:52:51568 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11569 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51570 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
571 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
572 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04573 ),
Gabriel Charette87cc1af2018-04-25 20:52:51574 False,
Gabriel Charettea44975052017-08-21 23:14:04575 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57576 ),
577 (
Dave Tapuska98199b612019-07-10 13:30:44578 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57579 (
580 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02581 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57582 ),
583 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16584 # Abseil's benchmarks never linked into chrome.
585 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38586 ),
587 (
Peter Kasting991618a62019-06-17 22:00:09588 r'/\bstd::stoi\b',
589 (
590 'std::stoi uses exceptions to communicate results. ',
591 'Use base::StringToInt() instead.',
592 ),
593 True,
594 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
595 ),
596 (
597 r'/\bstd::stol\b',
598 (
599 'std::stol uses exceptions to communicate results. ',
600 'Use base::StringToInt() instead.',
601 ),
602 True,
603 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
604 ),
605 (
606 r'/\bstd::stoul\b',
607 (
608 'std::stoul uses exceptions to communicate results. ',
609 'Use base::StringToUint() instead.',
610 ),
611 True,
612 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
613 ),
614 (
615 r'/\bstd::stoll\b',
616 (
617 'std::stoll uses exceptions to communicate results. ',
618 'Use base::StringToInt64() instead.',
619 ),
620 True,
621 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
622 ),
623 (
624 r'/\bstd::stoull\b',
625 (
626 'std::stoull uses exceptions to communicate results. ',
627 'Use base::StringToUint64() instead.',
628 ),
629 True,
630 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
631 ),
632 (
633 r'/\bstd::stof\b',
634 (
635 'std::stof uses exceptions to communicate results. ',
636 'For locale-independent values, e.g. reading numbers from disk',
637 'profiles, use base::StringToDouble().',
638 'For user-visible values, parse using ICU.',
639 ),
640 True,
641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
642 ),
643 (
644 r'/\bstd::stod\b',
645 (
646 'std::stod uses exceptions to communicate results. ',
647 'For locale-independent values, e.g. reading numbers from disk',
648 'profiles, use base::StringToDouble().',
649 'For user-visible values, parse using ICU.',
650 ),
651 True,
652 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
653 ),
654 (
655 r'/\bstd::stold\b',
656 (
657 'std::stold uses exceptions to communicate results. ',
658 'For locale-independent values, e.g. reading numbers from disk',
659 'profiles, use base::StringToDouble().',
660 'For user-visible values, parse using ICU.',
661 ),
662 True,
663 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
664 ),
665 (
Daniel Bratell69334cc2019-03-26 11:07:45666 r'/\bstd::to_string\b',
667 (
668 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09669 'For locale-independent strings, e.g. writing numbers to disk',
670 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45671 'For user-visible strings, use base::FormatNumber() and',
672 'the related functions in base/i18n/number_formatting.h.',
673 ),
Peter Kasting991618a62019-06-17 22:00:09674 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21675 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45676 ),
677 (
678 r'/\bstd::shared_ptr\b',
679 (
680 'std::shared_ptr should not be used. Use scoped_refptr instead.',
681 ),
682 True,
Ulan Degenbaev947043882021-02-10 14:02:31683 [
684 # Needed for interop with third-party library.
685 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57686 'array_buffer_contents\.(cc|h)',
Ulan Degenbaev947043882021-02-10 14:02:31687 'gin/array_buffer.cc',
688 'gin/array_buffer.h',
Alex Chau9eb03cdd52020-07-13 21:04:57689 'chrome/services/sharing/nearby/',
690 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21691 ),
692 (
Peter Kasting991618a62019-06-17 22:00:09693 r'/\bstd::weak_ptr\b',
694 (
695 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
696 ),
697 True,
698 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
699 ),
700 (
Daniel Bratell609102be2019-03-27 20:53:21701 r'/\blong long\b',
702 (
703 'long long is banned. Use stdint.h if you need a 64 bit number.',
704 ),
705 False, # Only a warning since it is already used.
706 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
707 ),
708 (
709 r'/\bstd::bind\b',
710 (
711 'std::bind is banned because of lifetime risks.',
712 'Use base::BindOnce or base::BindRepeating instead.',
713 ),
714 True,
715 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
716 ),
717 (
718 r'/\b#include <chrono>\b',
719 (
720 '<chrono> overlaps with Time APIs in base. Keep using',
721 'base classes.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
725 ),
726 (
727 r'/\b#include <exception>\b',
728 (
729 'Exceptions are banned and disabled in Chromium.',
730 ),
731 True,
732 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
733 ),
734 (
735 r'/\bstd::function\b',
736 (
737 'std::function is banned. Instead use base::Callback which directly',
738 'supports Chromium\'s weak pointers, ref counting and more.',
739 ),
Peter Kasting991618a62019-06-17 22:00:09740 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21741 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
742 ),
743 (
744 r'/\b#include <random>\b',
745 (
746 'Do not use any random number engines from <random>. Instead',
747 'use base::RandomBitGenerator.',
748 ),
749 True,
750 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
751 ),
752 (
Tom Andersona95e12042020-09-09 23:08:00753 r'/\b#include <X11/',
754 (
755 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
756 ),
757 True,
758 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
759 ),
760 (
Daniel Bratell609102be2019-03-27 20:53:21761 r'/\bstd::ratio\b',
762 (
763 'std::ratio is banned by the Google Style Guide.',
764 ),
765 True,
766 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45767 ),
768 (
Francois Doray43670e32017-09-27 12:40:38769 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
770 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
771 (
772 'Use the new API in base/threading/thread_restrictions.h.',
773 ),
Gabriel Charette04b138f2018-08-06 00:03:22774 False,
Francois Doray43670e32017-09-27 12:40:38775 (),
776 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38777 (
danakj7a2b7082019-05-21 21:13:51778 r'/\bbase::Bind\(',
779 (
780 'Please use base::Bind{Once,Repeating} instead',
781 'of base::Bind. (crbug.com/714018)',
782 ),
783 False,
Erik Staaba737d7602019-11-25 18:41:07784 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51785 ),
786 (
787 r'/\bbase::Callback[<:]',
788 (
789 'Please use base::{Once,Repeating}Callback instead',
790 'of base::Callback. (crbug.com/714018)',
791 ),
792 False,
Erik Staaba737d7602019-11-25 18:41:07793 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51794 ),
795 (
796 r'/\bbase::Closure\b',
797 (
798 'Please use base::{Once,Repeating}Closure instead',
799 'of base::Closure. (crbug.com/714018)',
800 ),
801 False,
Erik Staaba737d7602019-11-25 18:41:07802 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51803 ),
804 (
Alex Turnerb3ea38c2020-11-25 18:03:07805 r'/\bbase::CancelableCallback[<:]',
806 (
807 'Please use base::Cancelable{Once,Repeating}Callback instead',
808 'of base::CancelableCallback. (crbug.com/714018)',
809 ),
810 False,
811 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
812 ),
813 (
814 r'/\bbase::CancelableClosure\b',
815 (
816 'Please use base::Cancelable{Once,Repeating}Closure instead',
817 'of base::CancelableClosure. (crbug.com/714018)',
818 ),
819 False,
820 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
821 ),
822 (
Michael Giuffrida7f93d6922019-04-19 14:39:58823 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19824 (
825 'RunMessageLoop is deprecated, use RunLoop instead.',
826 ),
827 False,
828 (),
829 ),
830 (
Dave Tapuska98199b612019-07-10 13:30:44831 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19832 (
833 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
834 ),
835 False,
836 (),
837 ),
838 (
Dave Tapuska98199b612019-07-10 13:30:44839 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19840 (
841 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
842 "if you're convinced you need this.",
843 ),
844 False,
845 (),
846 ),
847 (
Dave Tapuska98199b612019-07-10 13:30:44848 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19849 (
850 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04851 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19852 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
853 'async events instead of flushing threads.',
854 ),
855 False,
856 (),
857 ),
858 (
859 r'MessageLoopRunner',
860 (
861 'MessageLoopRunner is deprecated, use RunLoop instead.',
862 ),
863 False,
864 (),
865 ),
866 (
Dave Tapuska98199b612019-07-10 13:30:44867 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19868 (
869 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
870 "gab@ if you found a use case where this is the only solution.",
871 ),
872 False,
873 (),
874 ),
875 (
Victor Costane48a2e82019-03-15 22:02:34876 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16877 (
Victor Costane48a2e82019-03-15 22:02:34878 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16879 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
880 ),
881 True,
882 (
883 r'^sql/initialization\.(cc|h)$',
884 r'^third_party/sqlite/.*\.(c|cc|h)$',
885 ),
886 ),
Matt Menke7f520a82018-03-28 21:38:37887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47889 (
890 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
891 'base::RandomShuffle instead.'
892 ),
893 True,
894 (),
895 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24896 (
897 'ios/web/public/test/http_server',
898 (
899 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
900 ),
901 False,
902 (),
903 ),
Robert Liao764c9492019-01-24 18:46:28904 (
905 'GetAddressOf',
906 (
907 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53908 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11909 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53910 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28911 ),
912 True,
913 (),
914 ),
Antonio Gomes07300d02019-03-13 20:59:57915 (
Ben Lewisa9514602019-04-29 17:53:05916 'SHFileOperation',
917 (
918 'SHFileOperation was deprecated in Windows Vista, and there are less ',
919 'complex functions to achieve the same goals. Use IFileOperation for ',
920 'any esoteric actions instead.'
921 ),
922 True,
923 (),
924 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18925 (
Cliff Smolinsky81951642019-04-30 21:39:51926 'StringFromGUID2',
927 (
928 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24929 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51930 ),
931 True,
932 (
933 r'/base/win/win_util_unittest.cc'
934 ),
935 ),
936 (
937 'StringFromCLSID',
938 (
939 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24940 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51941 ),
942 True,
943 (
944 r'/base/win/win_util_unittest.cc'
945 ),
946 ),
947 (
Avi Drissman7382afa02019-04-29 23:27:13948 'kCFAllocatorNull',
949 (
950 'The use of kCFAllocatorNull with the NoCopy creation of ',
951 'CoreFoundation types is prohibited.',
952 ),
953 True,
954 (),
955 ),
Oksana Zhuravlovafd247772019-05-16 16:57:29956 (
957 'mojo::ConvertTo',
958 (
959 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
960 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
961 'StringTraits if you would like to convert between custom types and',
962 'the wire format of mojom types.'
963 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22964 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29965 (
Wezf89dec092019-09-11 19:38:33966 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
967 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29968 r'^third_party/blink/.*\.(cc|h)$',
969 r'^content/renderer/.*\.(cc|h)$',
970 ),
971 ),
Robert Liao1d78df52019-11-11 20:02:01972 (
Oksana Zhuravlovac8222d22019-12-19 19:21:16973 'GetInterfaceProvider',
974 (
975 'InterfaceProvider is deprecated.',
976 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
977 'or Platform::GetBrowserInterfaceBroker.'
978 ),
979 False,
980 (),
981 ),
982 (
Robert Liao1d78df52019-11-11 20:02:01983 'CComPtr',
984 (
985 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
986 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
987 'details.'
988 ),
989 False,
990 (),
991 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:20992 (
993 r'/\b(IFACE|STD)METHOD_?\(',
994 (
995 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
996 'Instead, always use IFACEMETHODIMP in the declaration.'
997 ),
998 False,
999 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1000 ),
Allen Bauer53b43fb12020-03-12 17:21:471001 (
1002 'set_owned_by_client',
1003 (
1004 'set_owned_by_client is deprecated.',
1005 'views::View already owns the child views by default. This introduces ',
1006 'a competing ownership model which makes the code difficult to reason ',
1007 'about. See http://crbug.com/1044687 for more details.'
1008 ),
1009 False,
1010 (),
1011 ),
Eric Secklerbe6f48d2020-05-06 18:09:121012 (
1013 r'/\bTRACE_EVENT_ASYNC_',
1014 (
1015 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1016 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1017 ),
1018 False,
1019 (
1020 r'^base/trace_event/.*',
1021 r'^base/tracing/.*',
1022 ),
1023 ),
Sigurdur Asgeirsson9c1f87c2020-11-10 01:03:261024 (
1025 r'/\bScopedObserver',
1026 (
1027 'ScopedObserver is deprecated.',
1028 'Please use base::ScopedObservation for observing a single source,',
1029 'or base::ScopedMultiSourceObservation for observing multple sources',
1030 ),
1031 False,
1032 (),
1033 ),
Jan Wilken Dörrie60df2362021-04-08 19:44:211034 (
1035 r'/\bASCIIToUTF16\("(\\.|[^\\"])*"\)',
1036 (
1037 'base::ASCIIToUTF16 should not be used with a string literal.',
1038 'Consider using a UTF16 string literal (u"...") instead.',
1039 ),
1040 False,
1041 (),
1042 ),
1043 (
1044 r'/\bUTF8ToUTF16\("(\\.|[^\\"])*"\)',
1045 (
1046 'base::UTF8ToUTF16 should not be used with a string literal.',
1047 'Consider using a UTF16 string literal (u"...") instead.',
1048 ),
1049 False,
1050 (),
1051 ),
[email protected]127f18ec2012-06-16 05:05:591052)
1053
Mario Sanchez Prada2472cab2019-09-18 10:58:311054# Format: Sequence of tuples containing:
1055# * String pattern or, if starting with a slash, a regular expression.
1056# * Sequence of strings to show when the pattern matches.
1057_DEPRECATED_MOJO_TYPES = (
1058 (
1059 r'/\bmojo::AssociatedBinding\b',
1060 (
1061 'mojo::AssociatedBinding<Interface> is deprecated.',
1062 'Use mojo::AssociatedReceiver<Interface> instead.',
1063 ),
1064 ),
1065 (
1066 r'/\bmojo::AssociatedBindingSet\b',
1067 (
1068 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1069 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1070 ),
1071 ),
1072 (
1073 r'/\bmojo::AssociatedInterfacePtr\b',
1074 (
1075 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1076 'Use mojo::AssociatedRemote<Interface> instead.',
1077 ),
1078 ),
1079 (
1080 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1081 (
1082 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1083 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1084 ),
1085 ),
1086 (
1087 r'/\bmojo::AssociatedInterfaceRequest\b',
1088 (
1089 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1090 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1091 ),
1092 ),
1093 (
1094 r'/\bmojo::Binding\b',
1095 (
1096 'mojo::Binding<Interface> is deprecated.',
1097 'Use mojo::Receiver<Interface> instead.',
1098 ),
1099 ),
1100 (
1101 r'/\bmojo::BindingSet\b',
1102 (
1103 'mojo::BindingSet<Interface> is deprecated.',
1104 'Use mojo::ReceiverSet<Interface> instead.',
1105 ),
1106 ),
1107 (
1108 r'/\bmojo::InterfacePtr\b',
1109 (
1110 'mojo::InterfacePtr<Interface> is deprecated.',
1111 'Use mojo::Remote<Interface> instead.',
1112 ),
1113 ),
1114 (
1115 r'/\bmojo::InterfacePtrInfo\b',
1116 (
1117 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1118 'Use mojo::PendingRemote<Interface> instead.',
1119 ),
1120 ),
1121 (
1122 r'/\bmojo::InterfaceRequest\b',
1123 (
1124 'mojo::InterfaceRequest<Interface> is deprecated.',
1125 'Use mojo::PendingReceiver<Interface> instead.',
1126 ),
1127 ),
1128 (
1129 r'/\bmojo::MakeRequest\b',
1130 (
1131 'mojo::MakeRequest is deprecated.',
1132 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1133 ),
1134 ),
1135 (
1136 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1137 (
1138 'mojo::MakeRequest is deprecated.',
1139 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181140 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311141 ),
1142 ),
1143 (
1144 r'/\bmojo::MakeStrongBinding\b',
1145 (
1146 'mojo::MakeStrongBinding is deprecated.',
1147 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1148 'mojo::MakeSelfOwnedReceiver() instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::MakeStrongAssociatedBinding\b',
1153 (
1154 'mojo::MakeStrongAssociatedBinding is deprecated.',
1155 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1156 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1157 ),
1158 ),
1159 (
Gyuyoung Kim4952ba62020-07-07 07:33:441160 r'/\bmojo::StrongAssociatedBinding\b',
1161 (
1162 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1163 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1164 ),
1165 ),
1166 (
1167 r'/\bmojo::StrongBinding\b',
1168 (
1169 'mojo::StrongBinding<Interface> is deprecated.',
1170 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1171 ),
1172 ),
1173 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311174 r'/\bmojo::StrongAssociatedBindingSet\b',
1175 (
1176 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1177 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1178 ),
1179 ),
1180 (
1181 r'/\bmojo::StrongBindingSet\b',
1182 (
1183 'mojo::StrongBindingSet<Interface> is deprecated.',
1184 'Use mojo::UniqueReceiverSet<Interface> instead.',
1185 ),
1186 ),
1187)
wnwenbdc444e2016-05-25 13:44:151188
mlamouria82272622014-09-16 18:45:041189_IPC_ENUM_TRAITS_DEPRECATED = (
1190 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501191 'See http://www.chromium.org/Home/chromium-security/education/'
1192 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041193
Stephen Martinis97a394142018-06-07 23:06:051194_LONG_PATH_ERROR = (
1195 'Some files included in this CL have file names that are too long (> 200'
1196 ' characters). If committed, these files will cause issues on Windows. See'
1197 ' https://crbug.com/612667 for more details.'
1198)
1199
Shenghua Zhangbfaa38b82017-11-16 21:58:021200_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041201 r".*[\\/]BuildHooksAndroidImpl\.java",
1202 r".*[\\/]LicenseContentProvider\.java",
1203 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281204 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021205]
[email protected]127f18ec2012-06-16 05:05:591206
Mohamed Heikald048240a2019-11-12 16:57:371207# List of image extensions that are used as resources in chromium.
1208_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1209
Sean Kau46e29bc2017-08-28 16:31:161210# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401211_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041212 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401213 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041214 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1215 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041216 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431217 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161218]
1219
1220
[email protected]b00342e7f2013-03-26 16:21:541221_VALID_OS_MACROS = (
1222 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081223 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541224 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441225 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121226 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541227 'OS_BSD',
1228 'OS_CAT', # For testing.
1229 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041230 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541231 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371232 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541233 'OS_IOS',
1234 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441235 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541236 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211237 'OS_NACL_NONSFI',
1238 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121239 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541240 'OS_OPENBSD',
1241 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371242 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541243 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541244 'OS_WIN',
1245)
1246
1247
Andrew Grieveb773bad2020-06-05 18:00:381248# These are not checked on the public chromium-presubmit trybot.
1249# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041250# checkouts.
agrievef32bcc72016-04-04 14:57:401251_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381252 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381253]
1254
1255
1256_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041257 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361258 'base/android/jni_generator/jni_generator.pydeps',
1259 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361260 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041261 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361262 'build/android/gyp/aar.pydeps',
1263 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271264 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361265 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381266 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361267 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021268 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221269 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111270 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361271 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361272 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361273 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111274 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041275 'build/android/gyp/create_app_bundle_apks.pydeps',
1276 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361277 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121278 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091279 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221280 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001281 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361282 'build/android/gyp/desugar.pydeps',
1283 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421284 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041285 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361286 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361287 'build/android/gyp/filter_zip.pydeps',
1288 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361289 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361290 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581291 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361292 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141293 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261294 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011295 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041296 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361297 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361298 'build/android/gyp/merge_manifest.pydeps',
1299 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221300 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361301 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461302 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241303 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361304 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461305 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561306 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'build/android/incremental_install/generate_android_manifest.pydeps',
1308 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041309 'build/android/resource_sizes.pydeps',
1310 'build/android/test_runner.pydeps',
1311 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361312 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321314 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271315 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1316 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041317 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001318 'components/cronet/tools/generate_javadoc.pydeps',
1319 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381320 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001321 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381322 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041323 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181324 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041325 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421326 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1327 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131328 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061329 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221330 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401331]
1332
wnwenbdc444e2016-05-25 13:44:151333
agrievef32bcc72016-04-04 14:57:401334_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1335
1336
Eric Boren6fd2b932018-01-25 15:05:081337# Bypass the AUTHORS check for these accounts.
1338_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591339 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451340 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591341 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521342 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071343 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041344 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271345 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041346 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161347 for s in ('chromium-internal-autoroll',)
1348 ) | set('%[email protected]' % s
1349 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081350
1351
Daniel Bratell65b033262019-04-23 08:17:061352def _IsCPlusPlusFile(input_api, file_path):
1353 """Returns True if this file contains C++-like code (and not Python,
1354 Go, Java, MarkDown, ...)"""
1355
1356 ext = input_api.os_path.splitext(file_path)[1]
1357 # This list is compatible with CppChecker.IsCppFile but we should
1358 # consider adding ".c" to it. If we do that we can use this function
1359 # at more places in the code.
1360 return ext in (
1361 '.h',
1362 '.cc',
1363 '.cpp',
1364 '.m',
1365 '.mm',
1366 )
1367
1368def _IsCPlusPlusHeaderFile(input_api, file_path):
1369 return input_api.os_path.splitext(file_path)[1] == ".h"
1370
1371
1372def _IsJavaFile(input_api, file_path):
1373 return input_api.os_path.splitext(file_path)[1] == ".java"
1374
1375
1376def _IsProtoFile(input_api, file_path):
1377 return input_api.os_path.splitext(file_path)[1] == ".proto"
1378
Mohamed Heikal5e5b7922020-10-29 18:57:591379
1380def CheckNoUpstreamDepsOnClank(input_api, output_api):
1381 """Prevent additions of dependencies from the upstream repo on //clank."""
1382 # clank can depend on clank
1383 if input_api.change.RepositoryRoot().endswith('clank'):
1384 return []
1385 build_file_patterns = [
1386 r'(.+/)?BUILD\.gn',
1387 r'.+\.gni',
1388 ]
1389 excluded_files = [
1390 r'build[/\\]config[/\\]android[/\\]config\.gni'
1391 ]
1392 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1393
1394 error_message = 'Disallowed import on //clank in an upstream build file:'
1395
1396 def FilterFile(affected_file):
1397 return input_api.FilterSourceFile(
1398 affected_file,
1399 files_to_check=build_file_patterns,
1400 files_to_skip=excluded_files)
1401
1402 problems = []
1403 for f in input_api.AffectedSourceFiles(FilterFile):
1404 local_path = f.LocalPath()
1405 for line_number, line in f.ChangedContents():
1406 if (bad_pattern.search(line)):
1407 problems.append(
1408 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1409 if problems:
1410 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1411 else:
1412 return []
1413
1414
Saagar Sanghavifceeaae2020-08-12 16:40:361415def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191416 """Attempts to prevent use of functions intended only for testing in
1417 non-testing code. For now this is just a best-effort implementation
1418 that ignores header files and may have some false positives. A
1419 better implementation would probably need a proper C++ parser.
1420 """
1421 # We only scan .cc files and the like, as the declaration of
1422 # for-testing functions in header files are hard to distinguish from
1423 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491424 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191425
jochenc0d4808c2015-07-27 09:25:421426 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191427 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091428 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131429 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[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))
danakjf26536bf2020-09-10 00:46:131433 # Avoid a false positive in this case, where the method name, the ::, and
1434 # the closing { are all on different lines due to line wrapping.
1435 # HelperClassForTesting::
1436 # HelperClassForTesting(
1437 # args)
1438 # : member(0) {}
1439 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191440
1441 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441442 files_to_skip = (_EXCLUDED_PATHS +
1443 _TEST_CODE_EXCLUDED_PATHS +
1444 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191445 return input_api.FilterSourceFile(
1446 affected_file,
James Cook24a504192020-07-23 00:08:441447 files_to_check=file_inclusion_pattern,
1448 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191449
1450 problems = []
1451 for f in input_api.AffectedSourceFiles(FilterFile):
1452 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131453 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241454 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031455 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461456 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131457 not exclusion_pattern.search(line) and
1458 not allowlist_pattern.search(line) and
1459 not in_method_defn):
[email protected]55459852011-08-10 15:17:191460 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031461 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131462 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191463
1464 if problems:
[email protected]f7051d52013-04-02 18:31:421465 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031466 else:
1467 return []
[email protected]55459852011-08-10 15:17:191468
1469
Saagar Sanghavifceeaae2020-08-12 16:40:361470def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231471 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591472 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231473 """
1474 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1475 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1476 name_pattern = r'ForTest(s|ing)?'
1477 # Describes an occurrence of "ForTest*" inside a // comment.
1478 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501479 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551480 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231481 # Catch calls.
1482 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1483 # Ignore definitions. (Comments are ignored separately.)
1484 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1485
1486 problems = []
1487 sources = lambda x: input_api.FilterSourceFile(
1488 x,
James Cook24a504192020-07-23 00:08:441489 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1490 + input_api.DEFAULT_FILES_TO_SKIP),
1491 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231492 )
1493 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1494 local_path = f.LocalPath()
1495 is_inside_javadoc = False
1496 for line_number, line in f.ChangedContents():
1497 if is_inside_javadoc and javadoc_end_re.search(line):
1498 is_inside_javadoc = False
1499 if not is_inside_javadoc and javadoc_start_re.search(line):
1500 is_inside_javadoc = True
1501 if is_inside_javadoc:
1502 continue
1503 if (inclusion_re.search(line) and
1504 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501505 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 not exclusion_re.search(line)):
1507 problems.append(
1508 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1509
1510 if problems:
1511 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1512 else:
1513 return []
1514
1515
Saagar Sanghavifceeaae2020-08-12 16:40:361516def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541517 """Checks to make sure no .h files include <iostream>."""
1518 files = []
1519 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1520 input_api.re.MULTILINE)
1521 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1522 if not f.LocalPath().endswith('.h'):
1523 continue
1524 contents = input_api.ReadFile(f)
1525 if pattern.search(contents):
1526 files.append(f)
1527
1528 if len(files):
yolandyandaabc6d2016-04-18 18:29:391529 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061530 'Do not #include <iostream> in header files, since it inserts static '
1531 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541532 '#include <ostream>. See http://crbug.com/94794',
1533 files) ]
1534 return []
1535
Danil Chapovalov3518f362018-08-11 16:13:431536def _CheckNoStrCatRedefines(input_api, output_api):
1537 """Checks no windows headers with StrCat redefined are included directly."""
1538 files = []
1539 pattern_deny = input_api.re.compile(
1540 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1541 input_api.re.MULTILINE)
1542 pattern_allow = input_api.re.compile(
1543 r'^#include\s"base/win/windows_defines.inc"',
1544 input_api.re.MULTILINE)
1545 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1546 contents = input_api.ReadFile(f)
1547 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1548 files.append(f.LocalPath())
1549
1550 if len(files):
1551 return [output_api.PresubmitError(
1552 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1553 'directly since they pollute code with StrCat macro. Instead, '
1554 'include matching header from base/win. See http://crbug.com/856536',
1555 files) ]
1556 return []
1557
[email protected]10689ca2011-09-02 02:31:541558
Saagar Sanghavifceeaae2020-08-12 16:40:361559def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521560 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181561 problems = []
1562 for f in input_api.AffectedFiles():
1563 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1564 continue
1565
1566 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041567 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181568 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1569
1570 if not problems:
1571 return []
1572 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1573 '\n'.join(problems))]
1574
Saagar Sanghavifceeaae2020-08-12 16:40:361575def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341576 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1577
1578 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1579 instead of DISABLED_. To filter false positives, reports are only generated
1580 if a corresponding MAYBE_ line exists.
1581 """
1582 problems = []
1583
1584 # The following two patterns are looked for in tandem - is a test labeled
1585 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1586 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1587 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1588
1589 # This is for the case that a test is disabled on all platforms.
1590 full_disable_pattern = input_api.re.compile(
1591 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1592 input_api.re.MULTILINE)
1593
Katie Df13948e2018-09-25 07:33:441594 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341595 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1596 continue
1597
1598 # Search for MABYE_, DISABLE_ pairs.
1599 disable_lines = {} # Maps of test name to line number.
1600 maybe_lines = {}
1601 for line_num, line in f.ChangedContents():
1602 disable_match = disable_pattern.search(line)
1603 if disable_match:
1604 disable_lines[disable_match.group(1)] = line_num
1605 maybe_match = maybe_pattern.search(line)
1606 if maybe_match:
1607 maybe_lines[maybe_match.group(1)] = line_num
1608
1609 # Search for DISABLE_ occurrences within a TEST() macro.
1610 disable_tests = set(disable_lines.keys())
1611 maybe_tests = set(maybe_lines.keys())
1612 for test in disable_tests.intersection(maybe_tests):
1613 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1614
1615 contents = input_api.ReadFile(f)
1616 full_disable_match = full_disable_pattern.search(contents)
1617 if full_disable_match:
1618 problems.append(' %s' % f.LocalPath())
1619
1620 if not problems:
1621 return []
1622 return [
1623 output_api.PresubmitPromptWarning(
1624 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1625 '\n'.join(problems))
1626 ]
1627
[email protected]72df4e782012-06-21 16:28:181628
Saagar Sanghavifceeaae2020-08-12 16:40:361629def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571630 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521631 errors = []
Hans Wennborg944479f2020-06-25 21:39:251632 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521633 input_api.re.MULTILINE)
1634 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1635 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1636 continue
1637 for lnum, line in f.ChangedContents():
1638 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171639 errors.append(output_api.PresubmitError(
1640 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571641 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171642 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521643 return errors
1644
1645
Weilun Shia487fad2020-10-28 00:10:341646# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1647# more reliable way. See
1648# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191649
wnwenbdc444e2016-05-25 13:44:151650
Saagar Sanghavifceeaae2020-08-12 16:40:361651def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391652 """Check that FlakyTest annotation is our own instead of the android one"""
1653 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1654 files = []
1655 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1656 if f.LocalPath().endswith('Test.java'):
1657 if pattern.search(input_api.ReadFile(f)):
1658 files.append(f)
1659 if len(files):
1660 return [output_api.PresubmitError(
1661 'Use org.chromium.base.test.util.FlakyTest instead of '
1662 'android.test.FlakyTest',
1663 files)]
1664 return []
mcasasb7440c282015-02-04 14:52:191665
wnwenbdc444e2016-05-25 13:44:151666
Saagar Sanghavifceeaae2020-08-12 16:40:361667def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441668 """Make sure .DEPS.git is never modified manually."""
1669 if any(f.LocalPath().endswith('.DEPS.git') for f in
1670 input_api.AffectedFiles()):
1671 return [output_api.PresubmitError(
1672 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1673 'automated system based on what\'s in DEPS and your changes will be\n'
1674 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501675 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1676 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441677 'for more information')]
1678 return []
1679
1680
Saagar Sanghavifceeaae2020-08-12 16:40:361681def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471682 """Checks that DEPS file deps are from allowed_hosts."""
1683 # Run only if DEPS file has been modified to annoy fewer bystanders.
1684 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1685 return []
1686 # Outsource work to gclient verify
1687 try:
John Budorickf20c0042019-04-25 23:23:401688 gclient_path = input_api.os_path.join(
1689 input_api.PresubmitLocalPath(),
1690 'third_party', 'depot_tools', 'gclient.py')
1691 input_api.subprocess.check_output(
1692 [input_api.python_executable, gclient_path, 'verify'],
1693 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471694 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201695 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471696 return [output_api.PresubmitError(
1697 'DEPS file must have only git dependencies.',
1698 long_text=error.output)]
1699
1700
Mario Sanchez Prada2472cab2019-09-18 10:58:311701def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1702 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591703 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311704
1705 Returns an string composed of the name of the file, the line number where the
1706 match has been found and the additional text passed as |message| in case the
1707 target type name matches the text inside the line passed as parameter.
1708 """
Peng Huang9c5949a02020-06-11 19:20:541709 result = []
1710
danakjd18e8892020-12-17 17:42:011711 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1712 return result
1713 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541714 return result
1715
Mario Sanchez Prada2472cab2019-09-18 10:58:311716 matched = False
1717 if type_name[0:1] == '/':
1718 regex = type_name[1:]
1719 if input_api.re.search(regex, line):
1720 matched = True
1721 elif type_name in line:
1722 matched = True
1723
Mario Sanchez Prada2472cab2019-09-18 10:58:311724 if matched:
1725 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1726 for message_line in message:
1727 result.append(' %s' % message_line)
1728
1729 return result
1730
1731
Saagar Sanghavifceeaae2020-08-12 16:40:361732def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591733 """Make sure that banned functions are not used."""
1734 warnings = []
1735 errors = []
1736
James Cook24a504192020-07-23 00:08:441737 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151738 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441739 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151740 if input_api.re.match(item, local_path):
1741 return True
1742 return False
1743
Peter K. Lee6c03ccff2019-07-15 14:40:051744 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541745 local_path = affected_file.LocalPath()
1746 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1747 return False
1748 basename = input_api.os_path.basename(local_path)
1749 if 'ios' in basename.split('_'):
1750 return True
1751 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1752 if sep and 'ios' in local_path.split(sep):
1753 return True
1754 return False
1755
wnwenbdc444e2016-05-25 13:44:151756 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311757 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1758 func_name, message)
1759 if problems:
wnwenbdc444e2016-05-25 13:44:151760 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311761 errors.extend(problems)
1762 else:
1763 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151764
Eric Stevensona9a980972017-09-23 00:04:411765 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1766 for f in input_api.AffectedFiles(file_filter=file_filter):
1767 for line_num, line in f.ChangedContents():
1768 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1769 CheckForMatch(f, line_num, line, func_name, message, error)
1770
[email protected]127f18ec2012-06-16 05:05:591771 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1772 for f in input_api.AffectedFiles(file_filter=file_filter):
1773 for line_num, line in f.ChangedContents():
1774 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151775 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591776
Peter K. Lee6c03ccff2019-07-15 14:40:051777 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541778 for line_num, line in f.ChangedContents():
1779 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1780 CheckForMatch(f, line_num, line, func_name, message, error)
1781
Peter K. Lee6c03ccff2019-07-15 14:40:051782 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1783 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1784 for line_num, line in f.ChangedContents():
1785 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1786 CheckForMatch(f, line_num, line, func_name, message, error)
1787
[email protected]127f18ec2012-06-16 05:05:591788 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1789 for f in input_api.AffectedFiles(file_filter=file_filter):
1790 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491791 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441792 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491793 continue
wnwenbdc444e2016-05-25 13:44:151794 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591795
1796 result = []
1797 if (warnings):
1798 result.append(output_api.PresubmitPromptWarning(
1799 'Banned functions were used.\n' + '\n'.join(warnings)))
1800 if (errors):
1801 result.append(output_api.PresubmitError(
1802 'Banned functions were used.\n' + '\n'.join(errors)))
1803 return result
1804
1805
Michael Thiessen44457642020-02-06 00:24:151806def _CheckAndroidNoBannedImports(input_api, output_api):
1807 """Make sure that banned java imports are not used."""
1808 errors = []
1809
1810 def IsException(path, exceptions):
1811 for exception in exceptions:
1812 if (path.startswith(exception)):
1813 return True
1814 return False
1815
1816 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1817 for f in input_api.AffectedFiles(file_filter=file_filter):
1818 for line_num, line in f.ChangedContents():
1819 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1820 if IsException(f.LocalPath(), exceptions):
1821 continue;
1822 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1823 'import ' + import_name, message)
1824 if problems:
1825 errors.extend(problems)
1826 result = []
1827 if (errors):
1828 result.append(output_api.PresubmitError(
1829 'Banned imports were used.\n' + '\n'.join(errors)))
1830 return result
1831
1832
Saagar Sanghavifceeaae2020-08-12 16:40:361833def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311834 """Make sure that old Mojo types are not used."""
1835 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571836 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311837
Mario Sanchez Pradaaab91382019-12-19 08:57:091838 # For any path that is not an "ok" or an "error" path, a warning will be
1839 # raised if deprecated mojo types are found.
1840 ok_paths = ['components/arc']
1841 error_paths = ['third_party/blink', 'content']
1842
Mario Sanchez Prada2472cab2019-09-18 10:58:311843 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1844 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571845 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091846 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311847 continue
1848
1849 for line_num, line in f.ChangedContents():
1850 for func_name, message in _DEPRECATED_MOJO_TYPES:
1851 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1852 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571853
Mario Sanchez Prada2472cab2019-09-18 10:58:311854 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091855 # Raise errors inside |error_paths| and warnings everywhere else.
1856 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571857 errors.extend(problems)
1858 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311859 warnings.extend(problems)
1860
1861 result = []
1862 if (warnings):
1863 result.append(output_api.PresubmitPromptWarning(
1864 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571865 if (errors):
1866 result.append(output_api.PresubmitError(
1867 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311868 return result
1869
1870
Saagar Sanghavifceeaae2020-08-12 16:40:361871def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061872 """Make sure that banned functions are not used."""
1873 files = []
1874 pattern = input_api.re.compile(r'^#pragma\s+once',
1875 input_api.re.MULTILINE)
1876 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1877 if not f.LocalPath().endswith('.h'):
1878 continue
1879 contents = input_api.ReadFile(f)
1880 if pattern.search(contents):
1881 files.append(f)
1882
1883 if files:
1884 return [output_api.PresubmitError(
1885 'Do not use #pragma once in header files.\n'
1886 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1887 files)]
1888 return []
1889
[email protected]127f18ec2012-06-16 05:05:591890
Saagar Sanghavifceeaae2020-08-12 16:40:361891def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121892 """Checks to make sure we don't introduce use of foo ? true : false."""
1893 problems = []
1894 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1895 for f in input_api.AffectedFiles():
1896 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1897 continue
1898
1899 for line_num, line in f.ChangedContents():
1900 if pattern.match(line):
1901 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1902
1903 if not problems:
1904 return []
1905 return [output_api.PresubmitPromptWarning(
1906 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1907 '\n'.join(problems))]
1908
1909
Saagar Sanghavifceeaae2020-08-12 16:40:361910def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281911 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181912 change. Breaking - rules is an error, breaking ! rules is a
1913 warning.
1914 """
mohan.reddyf21db962014-10-16 12:26:471915 import sys
[email protected]55f9f382012-07-31 11:02:181916 # We need to wait until we have an input_api object and use this
1917 # roundabout construct to import checkdeps because this file is
1918 # eval-ed and thus doesn't have __file__.
1919 original_sys_path = sys.path
1920 try:
1921 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471922 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181923 import checkdeps
[email protected]55f9f382012-07-31 11:02:181924 from rules import Rule
1925 finally:
1926 # Restore sys.path to what it was before.
1927 sys.path = original_sys_path
1928
1929 added_includes = []
rhalavati08acd232017-04-03 07:23:281930 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241931 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181932 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061933 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501934 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081935 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061936 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501937 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081938 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061939 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501940 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081941 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181942
[email protected]26385172013-05-09 23:11:351943 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181944
1945 error_descriptions = []
1946 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281947 error_subjects = set()
1948 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361949
[email protected]55f9f382012-07-31 11:02:181950 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1951 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081952 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181953 description_with_path = '%s\n %s' % (path, rule_description)
1954 if rule_type == Rule.DISALLOW:
1955 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281956 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181957 else:
1958 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281959 warning_subjects.add("#includes")
1960
1961 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1962 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081963 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281964 description_with_path = '%s\n %s' % (path, rule_description)
1965 if rule_type == Rule.DISALLOW:
1966 error_descriptions.append(description_with_path)
1967 error_subjects.add("imports")
1968 else:
1969 warning_descriptions.append(description_with_path)
1970 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181971
Jinsuk Kim5a092672017-10-24 22:42:241972 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021973 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081974 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241975 description_with_path = '%s\n %s' % (path, rule_description)
1976 if rule_type == Rule.DISALLOW:
1977 error_descriptions.append(description_with_path)
1978 error_subjects.add("imports")
1979 else:
1980 warning_descriptions.append(description_with_path)
1981 warning_subjects.add("imports")
1982
[email protected]55f9f382012-07-31 11:02:181983 results = []
1984 if error_descriptions:
1985 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281986 'You added one or more %s that violate checkdeps rules.'
1987 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181988 error_descriptions))
1989 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421990 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281991 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181992 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281993 '%s? See relevant DEPS file(s) for details and contacts.' %
1994 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181995 warning_descriptions))
1996 return results
1997
1998
Saagar Sanghavifceeaae2020-08-12 16:40:361999def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222000 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152001 if input_api.platform == 'win32':
2002 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292003 checkperms_tool = input_api.os_path.join(
2004 input_api.PresubmitLocalPath(),
2005 'tools', 'checkperms', 'checkperms.py')
2006 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472007 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392008 with input_api.CreateTemporaryFile() as file_list:
2009 for f in input_api.AffectedFiles():
2010 # checkperms.py file/directory arguments must be relative to the
2011 # repository.
2012 file_list.write(f.LocalPath() + '\n')
2013 file_list.close()
2014 args += ['--file-list', file_list.name]
2015 try:
2016 input_api.subprocess.check_output(args)
2017 return []
2018 except input_api.subprocess.CalledProcessError as error:
2019 return [output_api.PresubmitError(
2020 'checkperms.py failed:',
2021 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222022
2023
Saagar Sanghavifceeaae2020-08-12 16:40:362024def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492025 """Makes sure we don't include ui/aura/window_property.h
2026 in header files.
2027 """
2028 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2029 errors = []
2030 for f in input_api.AffectedFiles():
2031 if not f.LocalPath().endswith('.h'):
2032 continue
2033 for line_num, line in f.ChangedContents():
2034 if pattern.match(line):
2035 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2036
2037 results = []
2038 if errors:
2039 results.append(output_api.PresubmitError(
2040 'Header files should not include ui/aura/window_property.h', errors))
2041 return results
2042
2043
[email protected]70ca77752012-11-20 03:45:032044def _CheckForVersionControlConflictsInFile(input_api, f):
2045 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2046 errors = []
2047 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162048 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232049 # First-level headers in markdown look a lot like version control
2050 # conflict markers. http://daringfireball.net/projects/markdown/basics
2051 continue
[email protected]70ca77752012-11-20 03:45:032052 if pattern.match(line):
2053 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2054 return errors
2055
2056
Saagar Sanghavifceeaae2020-08-12 16:40:362057def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032058 """Usually this is not intentional and will cause a compile failure."""
2059 errors = []
2060 for f in input_api.AffectedFiles():
2061 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2062
2063 results = []
2064 if errors:
2065 results.append(output_api.PresubmitError(
2066 'Version control conflict markers found, please resolve.', errors))
2067 return results
2068
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202069
Saagar Sanghavifceeaae2020-08-12 16:40:362070def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162071 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2072 errors = []
2073 for f in input_api.AffectedFiles():
2074 for line_num, line in f.ChangedContents():
2075 if pattern.search(line):
2076 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2077
2078 results = []
2079 if errors:
2080 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502081 'Found Google support URL addressed by answer number. Please replace '
2082 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162083 return results
2084
[email protected]70ca77752012-11-20 03:45:032085
Saagar Sanghavifceeaae2020-08-12 16:40:362086def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442087 def FilterFile(affected_file):
2088 """Filter function for use with input_api.AffectedSourceFiles,
2089 below. This filters out everything except non-test files from
2090 top-level directories that generally speaking should not hard-code
2091 service URLs (e.g. src/android_webview/, src/content/ and others).
2092 """
2093 return input_api.FilterSourceFile(
2094 affected_file,
James Cook24a504192020-07-23 00:08:442095 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2096 files_to_skip=(_EXCLUDED_PATHS +
2097 _TEST_CODE_EXCLUDED_PATHS +
2098 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442099
reillyi38965732015-11-16 18:27:332100 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2101 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462102 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2103 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442104 problems = [] # items are (filename, line_number, line)
2105 for f in input_api.AffectedSourceFiles(FilterFile):
2106 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462107 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442108 problems.append((f.LocalPath(), line_num, line))
2109
2110 if problems:
[email protected]f7051d52013-04-02 18:31:422111 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442112 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582113 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442114 [' %s:%d: %s' % (
2115 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032116 else:
2117 return []
[email protected]06e6d0ff2012-12-11 01:36:442118
2119
Saagar Sanghavifceeaae2020-08-12 16:40:362120def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292121 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2122 def FileFilter(affected_file):
2123 """Includes directories known to be Chrome OS only."""
2124 return input_api.FilterSourceFile(
2125 affected_file,
James Cook24a504192020-07-23 00:08:442126 files_to_check=('^ash/',
2127 '^chromeos/', # Top-level src/chromeos.
2128 '/chromeos/', # Any path component.
2129 '^components/arc',
2130 '^components/exo'),
2131 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292132
2133 prefs = []
2134 priority_prefs = []
2135 for f in input_api.AffectedFiles(file_filter=FileFilter):
2136 for line_num, line in f.ChangedContents():
2137 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2138 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2139 prefs.append(' %s' % line)
2140 if input_api.re.search(
2141 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2142 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2143 priority_prefs.append(' %s' % line)
2144
2145 results = []
2146 if (prefs):
2147 results.append(output_api.PresubmitPromptWarning(
2148 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2149 'by browser sync settings. If these prefs should be controlled by OS '
2150 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2151 if (priority_prefs):
2152 results.append(output_api.PresubmitPromptWarning(
2153 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2154 'controlled by browser sync settings. If these prefs should be '
2155 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2156 'instead.\n' + '\n'.join(prefs)))
2157 return results
2158
2159
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492160# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362161def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272162 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312163 The native_client_sdk directory is excluded because it has auto-generated PNG
2164 files for documentation.
[email protected]d2530012013-01-25 16:39:272165 """
[email protected]d2530012013-01-25 16:39:272166 errors = []
James Cook24a504192020-07-23 00:08:442167 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2168 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312169 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442170 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312171 for f in input_api.AffectedFiles(include_deletes=False,
2172 file_filter=file_filter):
2173 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272174
2175 results = []
2176 if errors:
2177 results.append(output_api.PresubmitError(
2178 'The name of PNG files should not have abbreviations. \n'
2179 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2180 'Contact [email protected] if you have questions.', errors))
2181 return results
2182
2183
Daniel Cheng4dcdb6b2017-04-13 08:30:172184def _ExtractAddRulesFromParsedDeps(parsed_deps):
2185 """Extract the rules that add dependencies from a parsed DEPS file.
2186
2187 Args:
2188 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2189 add_rules = set()
2190 add_rules.update([
2191 rule[1:] for rule in parsed_deps.get('include_rules', [])
2192 if rule.startswith('+') or rule.startswith('!')
2193 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502194 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172195 {}).iteritems():
2196 add_rules.update([
2197 rule[1:] for rule in rules
2198 if rule.startswith('+') or rule.startswith('!')
2199 ])
2200 return add_rules
2201
2202
2203def _ParseDeps(contents):
2204 """Simple helper for parsing DEPS files."""
2205 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172206 class _VarImpl:
2207
2208 def __init__(self, local_scope):
2209 self._local_scope = local_scope
2210
2211 def Lookup(self, var_name):
2212 """Implements the Var syntax."""
2213 try:
2214 return self._local_scope['vars'][var_name]
2215 except KeyError:
2216 raise Exception('Var is not defined: %s' % var_name)
2217
2218 local_scope = {}
2219 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172220 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592221 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172222 }
2223 exec contents in global_scope, local_scope
2224 return local_scope
2225
2226
2227def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592228 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412229 a set of DEPS entries that we should look up.
2230
2231 For a directory (rather than a specific filename) we fake a path to
2232 a specific filename by adding /DEPS. This is chosen as a file that
2233 will seldom or never be subject to per-file include_rules.
2234 """
[email protected]2b438d62013-11-14 17:54:142235 # We ignore deps entries on auto-generated directories.
2236 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082237
Daniel Cheng4dcdb6b2017-04-13 08:30:172238 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2239 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2240
2241 added_deps = new_deps.difference(old_deps)
2242
[email protected]2b438d62013-11-14 17:54:142243 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172244 for added_dep in added_deps:
2245 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2246 continue
2247 # Assume that a rule that ends in .h is a rule for a specific file.
2248 if added_dep.endswith('.h'):
2249 results.add(added_dep)
2250 else:
2251 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082252 return results
2253
2254
Saagar Sanghavifceeaae2020-08-12 16:40:362255def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552256 """When a dependency prefixed with + is added to a DEPS file, we
2257 want to make sure that the change is reviewed by an OWNER of the
2258 target file or directory, to avoid layering violations from being
2259 introduced. This check verifies that this happens.
2260 """
Joey Mou57048132021-02-26 22:17:552261 # We rely on Gerrit's code-owners to check approvals.
2262 # input_api.gerrit is always set for Chromium, but other projects
2263 # might not use Gerrit.
2264 if not input_api.gerrit:
2265 return []
Edward Lesmes44feb2332021-03-19 01:27:522266 if (input_api.change.issue and
2267 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232268 # Skip OWNERS check when Owners-Override label is approved. This is intended
2269 # for global owners, trusted bots, and on-call sheriffs. Review is still
2270 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522271 return []
Edward Lesmes6fba51082021-01-20 04:20:232272
Daniel Cheng4dcdb6b2017-04-13 08:30:172273 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242274
2275 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492276 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242277 for f in input_api.AffectedFiles(include_deletes=False,
2278 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552279 filename = input_api.os_path.basename(f.LocalPath())
2280 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172281 virtual_depended_on_files.update(_CalculateAddedDeps(
2282 input_api.os_path,
2283 '\n'.join(f.OldContents()),
2284 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552285
[email protected]e871964c2013-05-13 14:14:552286 if not virtual_depended_on_files:
2287 return []
2288
2289 if input_api.is_committing:
2290 if input_api.tbr:
2291 return [output_api.PresubmitNotifyResult(
2292 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272293 if input_api.dry_run:
2294 return [output_api.PresubmitNotifyResult(
2295 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552296 if not input_api.change.issue:
2297 return [output_api.PresubmitError(
2298 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402299 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552300 output = output_api.PresubmitError
2301 else:
2302 output = output_api.PresubmitNotifyResult
2303
tandriied3b7e12016-05-12 14:38:502304 owner_email, reviewers = (
2305 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2306 input_api,
Edward Lesmesa3846442021-02-08 20:20:032307 None,
tandriied3b7e12016-05-12 14:38:502308 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552309
2310 owner_email = owner_email or input_api.change.author_email
2311
Edward Lesmesa3846442021-02-08 20:20:032312 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2313 virtual_depended_on_files, reviewers.union([owner_email]), [])
2314 missing_files = [
2315 f for f in virtual_depended_on_files
2316 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412317
2318 # We strip the /DEPS part that was added by
2319 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2320 # directory.
2321 def StripDeps(path):
2322 start_deps = path.rfind('/DEPS')
2323 if start_deps != -1:
2324 return path[:start_deps]
2325 else:
2326 return path
2327 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552328 for path in missing_files]
2329
2330 if unapproved_dependencies:
2331 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152332 output('You need LGTM from owners of depends-on paths in DEPS that were '
2333 'modified in this CL:\n %s' %
2334 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032335 suggested_owners = input_api.owners_client.SuggestOwners(
2336 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152337 output_list.append(output(
2338 'Suggested missing target path OWNERS:\n %s' %
2339 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552340 return output_list
2341
2342 return []
2343
2344
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492345# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362346def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492347 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442348 files_to_skip = (_EXCLUDED_PATHS +
2349 _TEST_CODE_EXCLUDED_PATHS +
2350 input_api.DEFAULT_FILES_TO_SKIP +
2351 (r"^base[\\/]logging\.h$",
2352 r"^base[\\/]logging\.cc$",
2353 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2354 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2355 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2356 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2357 r"startup_browser_creator\.cc$",
2358 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2359 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2360 r"diagnostics_writer\.cc$",
2361 r"^chrome[\\/]chrome_cleaner[\\/].*",
2362 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2363 r"dll_hash_main\.cc$",
2364 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2365 r"^chromecast[\\/]",
2366 r"^cloud_print[\\/]",
2367 r"^components[\\/]browser_watcher[\\/]"
2368 r"dump_stability_report_main_win.cc$",
2369 r"^components[\\/]media_control[\\/]renderer[\\/]"
2370 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352371 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2372 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442373 r"^components[\\/]zucchini[\\/].*",
2374 # TODO(peter): Remove exception. https://crbug.com/534537
2375 r"^content[\\/]browser[\\/]notifications[\\/]"
2376 r"notification_event_dispatcher_impl\.cc$",
2377 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2378 r"gl_helper_benchmark\.cc$",
2379 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2380 r"^courgette[\\/]courgette_tool\.cc$",
2381 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2382 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2383 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082384 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542385 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2386 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442387 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2388 r"^ipc[\\/]ipc_logging\.cc$",
2389 r"^native_client_sdk[\\/]",
2390 r"^remoting[\\/]base[\\/]logging\.h$",
2391 r"^remoting[\\/]host[\\/].*",
2392 r"^sandbox[\\/]linux[\\/].*",
2393 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2394 r"dump_file_system.cc$",
2395 r"^tools[\\/]",
2396 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2397 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2398 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2399 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2400 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402401 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442402 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402403
thomasanderson625d3932017-03-29 07:16:582404 log_info = set([])
2405 printf = set([])
[email protected]85218562013-11-22 07:41:402406
2407 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582408 for _, line in f.ChangedContents():
2409 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2410 log_info.add(f.LocalPath())
2411 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2412 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372413
thomasanderson625d3932017-03-29 07:16:582414 if input_api.re.search(r"\bprintf\(", line):
2415 printf.add(f.LocalPath())
2416 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2417 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402418
2419 if log_info:
2420 return [output_api.PresubmitError(
2421 'These files spam the console log with LOG(INFO):',
2422 items=log_info)]
2423 if printf:
2424 return [output_api.PresubmitError(
2425 'These files spam the console log with printf/fprintf:',
2426 items=printf)]
2427 return []
2428
2429
Saagar Sanghavifceeaae2020-08-12 16:40:362430def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162431 """These types are all expected to hold locks while in scope and
2432 so should never be anonymous (which causes them to be immediately
2433 destroyed)."""
2434 they_who_must_be_named = [
2435 'base::AutoLock',
2436 'base::AutoReset',
2437 'base::AutoUnlock',
2438 'SkAutoAlphaRestore',
2439 'SkAutoBitmapShaderInstall',
2440 'SkAutoBlitterChoose',
2441 'SkAutoBounderCommit',
2442 'SkAutoCallProc',
2443 'SkAutoCanvasRestore',
2444 'SkAutoCommentBlock',
2445 'SkAutoDescriptor',
2446 'SkAutoDisableDirectionCheck',
2447 'SkAutoDisableOvalCheck',
2448 'SkAutoFree',
2449 'SkAutoGlyphCache',
2450 'SkAutoHDC',
2451 'SkAutoLockColors',
2452 'SkAutoLockPixels',
2453 'SkAutoMalloc',
2454 'SkAutoMaskFreeImage',
2455 'SkAutoMutexAcquire',
2456 'SkAutoPathBoundsUpdate',
2457 'SkAutoPDFRelease',
2458 'SkAutoRasterClipValidate',
2459 'SkAutoRef',
2460 'SkAutoTime',
2461 'SkAutoTrace',
2462 'SkAutoUnref',
2463 ]
2464 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2465 # bad: base::AutoLock(lock.get());
2466 # not bad: base::AutoLock lock(lock.get());
2467 bad_pattern = input_api.re.compile(anonymous)
2468 # good: new base::AutoLock(lock.get())
2469 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2470 errors = []
2471
2472 for f in input_api.AffectedFiles():
2473 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2474 continue
2475 for linenum, line in f.ChangedContents():
2476 if bad_pattern.search(line) and not good_pattern.search(line):
2477 errors.append('%s:%d' % (f.LocalPath(), linenum))
2478
2479 if errors:
2480 return [output_api.PresubmitError(
2481 'These lines create anonymous variables that need to be named:',
2482 items=errors)]
2483 return []
2484
2485
Saagar Sanghavifceeaae2020-08-12 16:40:362486def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532487 # Returns whether |template_str| is of the form <T, U...> for some types T
2488 # and U. Assumes that |template_str| is already in the form <...>.
2489 def HasMoreThanOneArg(template_str):
2490 # Level of <...> nesting.
2491 nesting = 0
2492 for c in template_str:
2493 if c == '<':
2494 nesting += 1
2495 elif c == '>':
2496 nesting -= 1
2497 elif c == ',' and nesting == 1:
2498 return True
2499 return False
2500
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492501 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102502 sources = lambda affected_file: input_api.FilterSourceFile(
2503 affected_file,
James Cook24a504192020-07-23 00:08:442504 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2505 input_api.DEFAULT_FILES_TO_SKIP),
2506 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552507
2508 # Pattern to capture a single "<...>" block of template arguments. It can
2509 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2510 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2511 # latter would likely require counting that < and > match, which is not
2512 # expressible in regular languages. Should the need arise, one can introduce
2513 # limited counting (matching up to a total number of nesting depth), which
2514 # should cover all practical cases for already a low nesting limit.
2515 template_arg_pattern = (
2516 r'<[^>]*' # Opening block of <.
2517 r'>([^<]*>)?') # Closing block of >.
2518 # Prefix expressing that whatever follows is not already inside a <...>
2519 # block.
2520 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102521 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552522 not_inside_template_arg_pattern
2523 + r'\bstd::unique_ptr'
2524 + template_arg_pattern
2525 + r'\(\)')
2526
2527 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2528 template_arg_no_array_pattern = (
2529 r'<[^>]*[^]]' # Opening block of <.
2530 r'>([^(<]*[^]]>)?') # Closing block of >.
2531 # Prefix saying that what follows is the start of an expression.
2532 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2533 # Suffix saying that what follows are call parentheses with a non-empty list
2534 # of arguments.
2535 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532536 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552537 return_construct_pattern = input_api.re.compile(
2538 start_of_expr_pattern
2539 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532540 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552541 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532542 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552543 + nonempty_arg_list_pattern)
2544
Vaclav Brozek851d9602018-04-04 16:13:052545 problems_constructor = []
2546 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102547 for f in input_api.AffectedSourceFiles(sources):
2548 for line_number, line in f.ChangedContents():
2549 # Disallow:
2550 # return std::unique_ptr<T>(foo);
2551 # bar = std::unique_ptr<T>(foo);
2552 # But allow:
2553 # return std::unique_ptr<T[]>(foo);
2554 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532555 # And also allow cases when the second template argument is present. Those
2556 # cases cannot be handled by std::make_unique:
2557 # return std::unique_ptr<T, U>(foo);
2558 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052559 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532560 return_construct_result = return_construct_pattern.search(line)
2561 if return_construct_result and not HasMoreThanOneArg(
2562 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052563 problems_constructor.append(
2564 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102565 # Disallow:
2566 # std::unique_ptr<T>()
2567 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052568 problems_nullptr.append(
2569 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2570
2571 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162572 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052573 errors.append(output_api.PresubmitError(
2574 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162575 problems_nullptr))
2576 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052577 errors.append(output_api.PresubmitError(
2578 'The following files use explicit std::unique_ptr constructor.'
2579 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162580 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102581 return errors
2582
2583
Saagar Sanghavifceeaae2020-08-12 16:40:362584def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082585 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522586 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082587 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522588 # If actions.xml is already included in the changelist, the PRESUBMIT
2589 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082590 return []
2591
Alexei Svitkine64505a92021-03-11 22:00:542592 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2593 files_to_skip = (_EXCLUDED_PATHS +
2594 _TEST_CODE_EXCLUDED_PATHS +
2595 input_api.DEFAULT_FILES_TO_SKIP )
2596 file_filter = lambda f: input_api.FilterSourceFile(
2597 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2598
[email protected]999261d2014-03-03 20:08:082599 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522600 current_actions = None
[email protected]999261d2014-03-03 20:08:082601 for f in input_api.AffectedFiles(file_filter=file_filter):
2602 for line_num, line in f.ChangedContents():
2603 match = input_api.re.search(action_re, line)
2604 if match:
[email protected]2f92dec2014-03-07 19:21:522605 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2606 # loaded only once.
2607 if not current_actions:
2608 with open('tools/metrics/actions/actions.xml') as actions_f:
2609 current_actions = actions_f.read()
2610 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082611 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522612 action = 'name="{0}"'.format(action_name)
2613 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082614 return [output_api.PresubmitPromptWarning(
2615 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522616 'tools/metrics/actions/actions.xml. Please run '
2617 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082618 % (f.LocalPath(), line_num, action_name))]
2619 return []
2620
2621
Daniel Cheng13ca61a882017-08-25 15:11:252622def _ImportJSONCommentEater(input_api):
2623 import sys
2624 sys.path = sys.path + [input_api.os_path.join(
2625 input_api.PresubmitLocalPath(),
2626 'tools', 'json_comment_eater')]
2627 import json_comment_eater
2628 return json_comment_eater
2629
2630
[email protected]99171a92014-06-03 08:44:472631def _GetJSONParseError(input_api, filename, eat_comments=True):
2632 try:
2633 contents = input_api.ReadFile(filename)
2634 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252635 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132636 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472637
2638 input_api.json.loads(contents)
2639 except ValueError as e:
2640 return e
2641 return None
2642
2643
2644def _GetIDLParseError(input_api, filename):
2645 try:
2646 contents = input_api.ReadFile(filename)
2647 idl_schema = input_api.os_path.join(
2648 input_api.PresubmitLocalPath(),
2649 'tools', 'json_schema_compiler', 'idl_schema.py')
2650 process = input_api.subprocess.Popen(
2651 [input_api.python_executable, idl_schema],
2652 stdin=input_api.subprocess.PIPE,
2653 stdout=input_api.subprocess.PIPE,
2654 stderr=input_api.subprocess.PIPE,
2655 universal_newlines=True)
2656 (_, error) = process.communicate(input=contents)
2657 return error or None
2658 except ValueError as e:
2659 return e
2660
2661
Saagar Sanghavifceeaae2020-08-12 16:40:362662def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472663 """Check that IDL and JSON files do not contain syntax errors."""
2664 actions = {
2665 '.idl': _GetIDLParseError,
2666 '.json': _GetJSONParseError,
2667 }
[email protected]99171a92014-06-03 08:44:472668 # Most JSON files are preprocessed and support comments, but these do not.
2669 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042670 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472671 ]
2672 # Only run IDL checker on files in these directories.
2673 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042674 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2675 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472676 ]
2677
2678 def get_action(affected_file):
2679 filename = affected_file.LocalPath()
2680 return actions.get(input_api.os_path.splitext(filename)[1])
2681
[email protected]99171a92014-06-03 08:44:472682 def FilterFile(affected_file):
2683 action = get_action(affected_file)
2684 if not action:
2685 return False
2686 path = affected_file.LocalPath()
2687
Erik Staab2dd72b12020-04-16 15:03:402688 if _MatchesFile(input_api,
2689 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2690 path):
[email protected]99171a92014-06-03 08:44:472691 return False
2692
2693 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162694 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472695 return False
2696 return True
2697
2698 results = []
2699 for affected_file in input_api.AffectedFiles(
2700 file_filter=FilterFile, include_deletes=False):
2701 action = get_action(affected_file)
2702 kwargs = {}
2703 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162704 _MatchesFile(input_api, json_no_comments_patterns,
2705 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472706 kwargs['eat_comments'] = False
2707 parse_error = action(input_api,
2708 affected_file.AbsoluteLocalPath(),
2709 **kwargs)
2710 if parse_error:
2711 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2712 (affected_file.LocalPath(), parse_error)))
2713 return results
2714
2715
Saagar Sanghavifceeaae2020-08-12 16:40:362716def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492717 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472718 import sys
[email protected]760deea2013-12-10 19:33:492719 original_sys_path = sys.path
2720 try:
2721 sys.path = sys.path + [input_api.os_path.join(
2722 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2723 import checkstyle
2724 finally:
2725 # Restore sys.path to what it was before.
2726 sys.path = original_sys_path
2727
2728 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092729 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442730 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492731
2732
Saagar Sanghavifceeaae2020-08-12 16:40:362733def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002734 """Checks to make sure devil is initialized correctly in python scripts."""
2735 script_common_initialize_pattern = input_api.re.compile(
2736 r'script_common\.InitializeEnvironment\(')
2737 devil_env_config_initialize = input_api.re.compile(
2738 r'devil_env\.config\.Initialize\(')
2739
2740 errors = []
2741
2742 sources = lambda affected_file: input_api.FilterSourceFile(
2743 affected_file,
James Cook24a504192020-07-23 00:08:442744 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2745 (r'^build[\\/]android[\\/]devil_chromium\.py',
2746 r'^third_party[\\/].*',)),
2747 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002748
2749 for f in input_api.AffectedSourceFiles(sources):
2750 for line_num, line in f.ChangedContents():
2751 if (script_common_initialize_pattern.search(line) or
2752 devil_env_config_initialize.search(line)):
2753 errors.append("%s:%d" % (f.LocalPath(), line_num))
2754
2755 results = []
2756
2757 if errors:
2758 results.append(output_api.PresubmitError(
2759 'Devil initialization should always be done using '
2760 'devil_chromium.Initialize() in the chromium project, to use better '
2761 'defaults for dependencies (ex. up-to-date version of adb).',
2762 errors))
2763
2764 return results
2765
2766
Sean Kau46e29bc2017-08-28 16:31:162767def _MatchesFile(input_api, patterns, path):
2768 for pattern in patterns:
2769 if input_api.re.search(pattern, path):
2770 return True
2771 return False
2772
2773
Daniel Cheng7052cdf2017-11-21 19:23:292774def _GetOwnersFilesToCheckForIpcOwners(input_api):
2775 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172776
Daniel Cheng7052cdf2017-11-21 19:23:292777 Returns:
2778 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2779 contain to cover IPC-related files with noparent reviewer rules.
2780 """
2781 # Whether or not a file affects IPC is (mostly) determined by a simple list
2782 # of filename patterns.
dchenge07de812016-06-20 19:27:172783 file_patterns = [
palmerb19a0932017-01-24 04:00:312784 # Legacy IPC:
dchenge07de812016-06-20 19:27:172785 '*_messages.cc',
2786 '*_messages*.h',
2787 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312788 # Mojo IPC:
dchenge07de812016-06-20 19:27:172789 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472790 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172791 '*_struct_traits*.*',
2792 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312793 '*.typemap',
2794 # Android native IPC:
2795 '*.aidl',
2796 # Blink uses a different file naming convention:
2797 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472798 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172799 '*StructTraits*.*',
2800 '*TypeConverter*.*',
2801 ]
2802
scottmg7a6ed5ba2016-11-04 18:22:042803 # These third_party directories do not contain IPCs, but contain files
2804 # matching the above patterns, which trigger false positives.
2805 exclude_paths = [
2806 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162807 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232808 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292809 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542810 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162811 # These files are just used to communicate between class loaders running
2812 # in the same process.
2813 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572814 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2815
scottmg7a6ed5ba2016-11-04 18:22:042816 ]
2817
dchenge07de812016-06-20 19:27:172818 # Dictionary mapping an OWNERS file path to Patterns.
2819 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2820 # rules ) to a PatternEntry.
2821 # PatternEntry is a dictionary with two keys:
2822 # - 'files': the files that are matched by this pattern
2823 # - 'rules': the per-file rules needed for this pattern
2824 # For example, if we expect OWNERS file to contain rules for *.mojom and
2825 # *_struct_traits*.*, Patterns might look like this:
2826 # {
2827 # '*.mojom': {
2828 # 'files': ...,
2829 # 'rules': [
2830 # 'per-file *.mojom=set noparent',
2831 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2832 # ],
2833 # },
2834 # '*_struct_traits*.*': {
2835 # 'files': ...,
2836 # 'rules': [
2837 # 'per-file *_struct_traits*.*=set noparent',
2838 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2839 # ],
2840 # },
2841 # }
2842 to_check = {}
2843
Daniel Cheng13ca61a882017-08-25 15:11:252844 def AddPatternToCheck(input_file, pattern):
2845 owners_file = input_api.os_path.join(
2846 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2847 if owners_file not in to_check:
2848 to_check[owners_file] = {}
2849 if pattern not in to_check[owners_file]:
2850 to_check[owners_file][pattern] = {
2851 'files': [],
2852 'rules': [
2853 'per-file %s=set noparent' % pattern,
2854 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2855 ]
2856 }
Vaclav Brozekd5de76a2018-03-17 07:57:502857 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252858
dchenge07de812016-06-20 19:27:172859 # Iterate through the affected files to see what we actually need to check
2860 # for. We should only nag patch authors about per-file rules if a file in that
2861 # directory would match that pattern. If a directory only contains *.mojom
2862 # files and no *_messages*.h files, we should only nag about rules for
2863 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252864 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262865 # Manifest files don't have a strong naming convention. Instead, try to find
2866 # affected .cc and .h files which look like they contain a manifest
2867 # definition.
2868 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2869 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2870 if (manifest_pattern.search(f.LocalPath()) and not
2871 test_manifest_pattern.search(f.LocalPath())):
2872 # We expect all actual service manifest files to contain at least one
2873 # qualified reference to service_manager::Manifest.
2874 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252875 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172876 for pattern in file_patterns:
2877 if input_api.fnmatch.fnmatch(
2878 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042879 skip = False
2880 for exclude in exclude_paths:
2881 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2882 skip = True
2883 break
2884 if skip:
2885 continue
Daniel Cheng13ca61a882017-08-25 15:11:252886 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172887 break
2888
Daniel Cheng7052cdf2017-11-21 19:23:292889 return to_check
2890
2891
Wez17c66962020-04-29 15:26:032892def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2893 """Adds OWNERS files to check for correct Fuchsia security owners."""
2894
2895 file_patterns = [
2896 # Component specifications.
2897 '*.cml', # Component Framework v2.
2898 '*.cmx', # Component Framework v1.
2899
2900 # Fuchsia IDL protocol specifications.
2901 '*.fidl',
2902 ]
2903
Joshua Peraza1ca6d392020-12-08 00:14:092904 # Don't check for owners files for changes in these directories.
2905 exclude_paths = [
2906 'third_party/crashpad/*',
2907 ]
2908
Wez17c66962020-04-29 15:26:032909 def AddPatternToCheck(input_file, pattern):
2910 owners_file = input_api.os_path.join(
2911 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2912 if owners_file not in to_check:
2913 to_check[owners_file] = {}
2914 if pattern not in to_check[owners_file]:
2915 to_check[owners_file][pattern] = {
2916 'files': [],
2917 'rules': [
2918 'per-file %s=set noparent' % pattern,
2919 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2920 ]
2921 }
2922 to_check[owners_file][pattern]['files'].append(input_file)
2923
2924 # Iterate through the affected files to see what we actually need to check
2925 # for. We should only nag patch authors about per-file rules if a file in that
2926 # directory would match that pattern.
2927 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092928 skip = False
2929 for exclude in exclude_paths:
2930 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2931 skip = True
2932 if skip:
2933 continue
2934
Wez17c66962020-04-29 15:26:032935 for pattern in file_patterns:
2936 if input_api.fnmatch.fnmatch(
2937 input_api.os_path.basename(f.LocalPath()), pattern):
2938 AddPatternToCheck(f, pattern)
2939 break
2940
2941 return to_check
2942
2943
Saagar Sanghavifceeaae2020-08-12 16:40:362944def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292945 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2946 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032947 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292948
2949 if to_check:
2950 # If there are any OWNERS files to check, there are IPC-related changes in
2951 # this CL. Auto-CC the review list.
2952 output_api.AppendCC('[email protected]')
2953
2954 # Go through the OWNERS files to check, filtering out rules that are already
2955 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172956 for owners_file, patterns in to_check.iteritems():
2957 try:
2958 with file(owners_file) as f:
2959 lines = set(f.read().splitlines())
2960 for entry in patterns.itervalues():
2961 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2962 ]
2963 except IOError:
2964 # No OWNERS file, so all the rules are definitely missing.
2965 continue
2966
2967 # All the remaining lines weren't found in OWNERS files, so emit an error.
2968 errors = []
2969 for owners_file, patterns in to_check.iteritems():
2970 missing_lines = []
2971 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502972 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172973 missing_lines.extend(entry['rules'])
2974 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2975 if missing_lines:
2976 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052977 'Because of the presence of files:\n%s\n\n'
2978 '%s needs the following %d lines added:\n\n%s' %
2979 ('\n'.join(files), owners_file, len(missing_lines),
2980 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172981
2982 results = []
2983 if errors:
vabrf5ce3bf92016-07-11 14:52:412984 if input_api.is_committing:
2985 output = output_api.PresubmitError
2986 else:
2987 output = output_api.PresubmitPromptWarning
2988 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592989 'Found OWNERS files that need to be updated for IPC security ' +
2990 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172991 long_text='\n\n'.join(errors)))
2992
2993 return results
2994
2995
Robert Sesek2c905332020-05-06 23:17:132996def _GetFilesUsingSecurityCriticalFunctions(input_api):
2997 """Checks affected files for changes to security-critical calls. This
2998 function checks the full change diff, to catch both additions/changes
2999 and removals.
3000
3001 Returns a dict keyed by file name, and the value is a set of detected
3002 functions.
3003 """
3004 # Map of function pretty name (displayed in an error) to the pattern to
3005 # match it with.
3006 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373007 'content::GetServiceSandboxType<>()':
3008 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133009 }
3010 _PATTERNS_TO_CHECK = {
3011 k: input_api.re.compile(v)
3012 for k, v in _PATTERNS_TO_CHECK.items()
3013 }
3014
3015 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3016 files_to_functions = {}
3017 for f in input_api.AffectedFiles():
3018 diff = f.GenerateScmDiff()
3019 for line in diff.split('\n'):
3020 # Not using just RightHandSideLines() because removing a
3021 # call to a security-critical function can be just as important
3022 # as adding or changing the arguments.
3023 if line.startswith('-') or (line.startswith('+') and
3024 not line.startswith('++')):
3025 for name, pattern in _PATTERNS_TO_CHECK.items():
3026 if pattern.search(line):
3027 path = f.LocalPath()
3028 if not path in files_to_functions:
3029 files_to_functions[path] = set()
3030 files_to_functions[path].add(name)
3031 return files_to_functions
3032
3033
Saagar Sanghavifceeaae2020-08-12 16:40:363034def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133035 """Checks that changes involving security-critical functions are reviewed
3036 by the security team.
3037 """
3038 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123039 if not len(files_to_functions):
3040 return []
Robert Sesek2c905332020-05-06 23:17:133041
Edward Lesmes1e9fade2021-02-08 20:31:123042 owner_email, reviewers = (
3043 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3044 input_api,
3045 None,
3046 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133047
Edward Lesmes1e9fade2021-02-08 20:31:123048 # Load the OWNERS file for security changes.
3049 owners_file = 'ipc/SECURITY_OWNERS'
3050 security_owners = input_api.owners_client.ListOwners(owners_file)
3051 has_security_owner = any([owner in reviewers for owner in security_owners])
3052 if has_security_owner:
3053 return []
Robert Sesek2c905332020-05-06 23:17:133054
Edward Lesmes1e9fade2021-02-08 20:31:123055 msg = 'The following files change calls to security-sensive functions\n' \
3056 'that need to be reviewed by {}.\n'.format(owners_file)
3057 for path, names in files_to_functions.items():
3058 msg += ' {}\n'.format(path)
3059 for name in names:
3060 msg += ' {}\n'.format(name)
3061 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133062
Edward Lesmes1e9fade2021-02-08 20:31:123063 if input_api.is_committing:
3064 output = output_api.PresubmitError
3065 else:
3066 output = output_api.PresubmitNotifyResult
3067 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133068
3069
Saagar Sanghavifceeaae2020-08-12 16:40:363070def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263071 """Checks that set noparent is only used together with an OWNERS file in
3072 //build/OWNERS.setnoparent (see also
3073 //docs/code_reviews.md#owners-files-details)
3074 """
3075 errors = []
3076
3077 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3078 allowed_owners_files = set()
3079 with open(allowed_owners_files_file, 'r') as f:
3080 for line in f:
3081 line = line.strip()
3082 if not line or line.startswith('#'):
3083 continue
3084 allowed_owners_files.add(line)
3085
3086 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3087
3088 for f in input_api.AffectedFiles(include_deletes=False):
3089 if not f.LocalPath().endswith('OWNERS'):
3090 continue
3091
3092 found_owners_files = set()
3093 found_set_noparent_lines = dict()
3094
3095 # Parse the OWNERS file.
3096 for lineno, line in enumerate(f.NewContents(), 1):
3097 line = line.strip()
3098 if line.startswith('set noparent'):
3099 found_set_noparent_lines[''] = lineno
3100 if line.startswith('file://'):
3101 if line in allowed_owners_files:
3102 found_owners_files.add('')
3103 if line.startswith('per-file'):
3104 match = per_file_pattern.match(line)
3105 if match:
3106 glob = match.group(1).strip()
3107 directive = match.group(2).strip()
3108 if directive == 'set noparent':
3109 found_set_noparent_lines[glob] = lineno
3110 if directive.startswith('file://'):
3111 if directive in allowed_owners_files:
3112 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153113
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263114 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403115 # listed in build/OWNERS.setnoparent. An exception is made for top level
3116 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143117 if (f.LocalPath().count('/') != 1 and
3118 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403119 for set_noparent_line in found_set_noparent_lines:
3120 if set_noparent_line in found_owners_files:
3121 continue
3122 errors.append(' %s:%d' % (f.LocalPath(),
3123 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263124
3125 results = []
3126 if errors:
3127 if input_api.is_committing:
3128 output = output_api.PresubmitError
3129 else:
3130 output = output_api.PresubmitPromptWarning
3131 results.append(output(
3132 'Found the following "set noparent" restrictions in OWNERS files that '
3133 'do not include owners from build/OWNERS.setnoparent:',
3134 long_text='\n\n'.join(errors)))
3135 return results
3136
3137
Saagar Sanghavifceeaae2020-08-12 16:40:363138def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313139 """Checks that added or removed lines in non third party affected
3140 header files do not lead to new useless class or struct forward
3141 declaration.
jbriance9e12f162016-11-25 07:57:503142 """
3143 results = []
3144 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3145 input_api.re.MULTILINE)
3146 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3147 input_api.re.MULTILINE)
3148 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313149 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193150 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493151 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313152 continue
3153
jbriance9e12f162016-11-25 07:57:503154 if not f.LocalPath().endswith('.h'):
3155 continue
3156
3157 contents = input_api.ReadFile(f)
3158 fwd_decls = input_api.re.findall(class_pattern, contents)
3159 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3160
3161 useless_fwd_decls = []
3162 for decl in fwd_decls:
3163 count = sum(1 for _ in input_api.re.finditer(
3164 r'\b%s\b' % input_api.re.escape(decl), contents))
3165 if count == 1:
3166 useless_fwd_decls.append(decl)
3167
3168 if not useless_fwd_decls:
3169 continue
3170
3171 for line in f.GenerateScmDiff().splitlines():
3172 if (line.startswith('-') and not line.startswith('--') or
3173 line.startswith('+') and not line.startswith('++')):
3174 for decl in useless_fwd_decls:
3175 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3176 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243177 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503178 (f.LocalPath(), decl)))
3179 useless_fwd_decls.remove(decl)
3180
3181 return results
3182
Jinsong Fan91ebbbd2019-04-16 14:57:173183def _CheckAndroidDebuggableBuild(input_api, output_api):
3184 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3185 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3186 this is a debuggable build of Android.
3187 """
3188 build_type_check_pattern = input_api.re.compile(
3189 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3190
3191 errors = []
3192
3193 sources = lambda affected_file: input_api.FilterSourceFile(
3194 affected_file,
James Cook24a504192020-07-23 00:08:443195 files_to_skip=(_EXCLUDED_PATHS +
3196 _TEST_CODE_EXCLUDED_PATHS +
3197 input_api.DEFAULT_FILES_TO_SKIP +
3198 (r"^android_webview[\\/]support_library[\\/]"
3199 "boundary_interfaces[\\/]",
3200 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3201 r'^third_party[\\/].*',
3202 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3203 r"webview[\\/]chromium[\\/]License.*",)),
3204 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173205
3206 for f in input_api.AffectedSourceFiles(sources):
3207 for line_num, line in f.ChangedContents():
3208 if build_type_check_pattern.search(line):
3209 errors.append("%s:%d" % (f.LocalPath(), line_num))
3210
3211 results = []
3212
3213 if errors:
3214 results.append(output_api.PresubmitPromptWarning(
3215 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3216 ' Please use BuildInfo.isDebugAndroid() instead.',
3217 errors))
3218
3219 return results
jbriance9e12f162016-11-25 07:57:503220
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493221# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293222def _CheckAndroidToastUsage(input_api, output_api):
3223 """Checks that code uses org.chromium.ui.widget.Toast instead of
3224 android.widget.Toast (Chromium Toast doesn't force hardware
3225 acceleration on low-end devices, saving memory).
3226 """
3227 toast_import_pattern = input_api.re.compile(
3228 r'^import android\.widget\.Toast;$')
3229
3230 errors = []
3231
3232 sources = lambda affected_file: input_api.FilterSourceFile(
3233 affected_file,
James Cook24a504192020-07-23 00:08:443234 files_to_skip=(_EXCLUDED_PATHS +
3235 _TEST_CODE_EXCLUDED_PATHS +
3236 input_api.DEFAULT_FILES_TO_SKIP +
3237 (r'^chromecast[\\/].*',
3238 r'^remoting[\\/].*')),
3239 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293240
3241 for f in input_api.AffectedSourceFiles(sources):
3242 for line_num, line in f.ChangedContents():
3243 if toast_import_pattern.search(line):
3244 errors.append("%s:%d" % (f.LocalPath(), line_num))
3245
3246 results = []
3247
3248 if errors:
3249 results.append(output_api.PresubmitError(
3250 'android.widget.Toast usage is detected. Android toasts use hardware'
3251 ' acceleration, and can be\ncostly on low-end devices. Please use'
3252 ' org.chromium.ui.widget.Toast instead.\n'
3253 'Contact [email protected] if you have any questions.',
3254 errors))
3255
3256 return results
3257
3258
dgnaa68d5e2015-06-10 10:08:223259def _CheckAndroidCrLogUsage(input_api, output_api):
3260 """Checks that new logs using org.chromium.base.Log:
3261 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513262 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223263 """
pkotwicza1dd0b002016-05-16 14:41:043264
torne89540622017-03-24 19:41:303265 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043266 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303267 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043268 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303269 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043270 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3271 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093272 # The customtabs_benchmark is a small app that does not depend on Chromium
3273 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043274 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043275 ]
3276
dgnaa68d5e2015-06-10 10:08:223277 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123278 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3279 class_in_base_pattern = input_api.re.compile(
3280 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3281 has_some_log_import_pattern = input_api.re.compile(
3282 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223283 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553284 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223285 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463286 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553287 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223288
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463289 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443290 sources = lambda x: input_api.FilterSourceFile(x,
3291 files_to_check=[r'.*\.java$'],
3292 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123293
dgnaa68d5e2015-06-10 10:08:223294 tag_decl_errors = []
3295 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123296 tag_errors = []
dgn38736db2015-09-18 19:20:513297 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123298 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223299
3300 for f in input_api.AffectedSourceFiles(sources):
3301 file_content = input_api.ReadFile(f)
3302 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223303 # Per line checks
dgn87d9fb62015-06-12 09:15:123304 if (cr_log_import_pattern.search(file_content) or
3305 (class_in_base_pattern.search(file_content) and
3306 not has_some_log_import_pattern.search(file_content))):
3307 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223308 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553309 if rough_log_decl_pattern.search(line):
3310 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223311
3312 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123313 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223314 if match:
3315 has_modified_logs = True
3316
3317 # Make sure it uses "TAG"
3318 if not match.group('tag') == 'TAG':
3319 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123320 else:
3321 # Report non cr Log function calls in changed lines
3322 for line_num, line in f.ChangedContents():
3323 if log_call_pattern.search(line):
3324 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223325
3326 # Per file checks
3327 if has_modified_logs:
3328 # Make sure the tag is using the "cr" prefix and is not too long
3329 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513330 tag_name = match.group('name') if match else None
3331 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223332 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513333 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223334 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513335 elif '.' in tag_name:
3336 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223337
3338 results = []
3339 if tag_decl_errors:
3340 results.append(output_api.PresubmitPromptWarning(
3341 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513342 '"private static final String TAG = "<package tag>".\n'
3343 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223344 tag_decl_errors))
3345
3346 if tag_length_errors:
3347 results.append(output_api.PresubmitError(
3348 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513349 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223350 tag_length_errors))
3351
3352 if tag_errors:
3353 results.append(output_api.PresubmitPromptWarning(
3354 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3355 tag_errors))
3356
dgn87d9fb62015-06-12 09:15:123357 if util_log_errors:
dgn4401aa52015-04-29 16:26:173358 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123359 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3360 util_log_errors))
3361
dgn38736db2015-09-18 19:20:513362 if tag_with_dot_errors:
3363 results.append(output_api.PresubmitPromptWarning(
3364 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3365 tag_with_dot_errors))
3366
dgn4401aa52015-04-29 16:26:173367 return results
3368
3369
Yoland Yanb92fa522017-08-28 17:37:063370def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3371 """Checks that junit.framework.* is no longer used."""
3372 deprecated_junit_framework_pattern = input_api.re.compile(
3373 r'^import junit\.framework\..*;',
3374 input_api.re.MULTILINE)
3375 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443376 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063377 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133378 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063379 for line_num, line in f.ChangedContents():
3380 if deprecated_junit_framework_pattern.search(line):
3381 errors.append("%s:%d" % (f.LocalPath(), line_num))
3382
3383 results = []
3384 if errors:
3385 results.append(output_api.PresubmitError(
3386 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3387 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3388 ' if you have any question.', errors))
3389 return results
3390
3391
3392def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3393 """Checks that if new Java test classes have inheritance.
3394 Either the new test class is JUnit3 test or it is a JUnit4 test class
3395 with a base class, either case is undesirable.
3396 """
3397 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3398
3399 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443400 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063401 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133402 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063403 if not f.OldContents():
3404 class_declaration_start_flag = False
3405 for line_num, line in f.ChangedContents():
3406 if class_declaration_pattern.search(line):
3407 class_declaration_start_flag = True
3408 if class_declaration_start_flag and ' extends ' in line:
3409 errors.append('%s:%d' % (f.LocalPath(), line_num))
3410 if '{' in line:
3411 class_declaration_start_flag = False
3412
3413 results = []
3414 if errors:
3415 results.append(output_api.PresubmitPromptWarning(
3416 'The newly created files include Test classes that inherits from base'
3417 ' class. Please do not use inheritance in JUnit4 tests or add new'
3418 ' JUnit3 tests. Contact [email protected] if you have any'
3419 ' questions.', errors))
3420 return results
3421
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203422
yolandyan45001472016-12-21 21:12:423423def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3424 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3425 deprecated_annotation_import_pattern = input_api.re.compile(
3426 r'^import android\.test\.suitebuilder\.annotation\..*;',
3427 input_api.re.MULTILINE)
3428 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443429 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423430 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133431 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423432 for line_num, line in f.ChangedContents():
3433 if deprecated_annotation_import_pattern.search(line):
3434 errors.append("%s:%d" % (f.LocalPath(), line_num))
3435
3436 results = []
3437 if errors:
3438 results.append(output_api.PresubmitError(
3439 'Annotations in android.test.suitebuilder.annotation have been'
3440 ' deprecated since API level 24. Please use android.support.test.filters'
3441 ' from //third_party/android_support_test_runner:runner_java instead.'
3442 ' Contact [email protected] if you have any questions.', errors))
3443 return results
3444
3445
agrieve7b6479d82015-10-07 14:24:223446def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3447 """Checks if MDPI assets are placed in a correct directory."""
3448 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3449 ('/res/drawable/' in f.LocalPath() or
3450 '/res/drawable-ldrtl/' in f.LocalPath()))
3451 errors = []
3452 for f in input_api.AffectedFiles(include_deletes=False,
3453 file_filter=file_filter):
3454 errors.append(' %s' % f.LocalPath())
3455
3456 results = []
3457 if errors:
3458 results.append(output_api.PresubmitError(
3459 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3460 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3461 '/res/drawable-ldrtl/.\n'
3462 'Contact [email protected] if you have questions.', errors))
3463 return results
3464
3465
Nate Fischer535972b2017-09-16 01:06:183466def _CheckAndroidWebkitImports(input_api, output_api):
3467 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353468 android.webview.ValueCallback except in the WebView glue layer
3469 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183470 """
3471 valuecallback_import_pattern = input_api.re.compile(
3472 r'^import android\.webkit\.ValueCallback;$')
3473
3474 errors = []
3475
3476 sources = lambda affected_file: input_api.FilterSourceFile(
3477 affected_file,
James Cook24a504192020-07-23 00:08:443478 files_to_skip=(_EXCLUDED_PATHS +
3479 _TEST_CODE_EXCLUDED_PATHS +
3480 input_api.DEFAULT_FILES_TO_SKIP +
3481 (r'^android_webview[\\/]glue[\\/].*',
3482 r'^weblayer[\\/].*',)),
3483 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183484
3485 for f in input_api.AffectedSourceFiles(sources):
3486 for line_num, line in f.ChangedContents():
3487 if valuecallback_import_pattern.search(line):
3488 errors.append("%s:%d" % (f.LocalPath(), line_num))
3489
3490 results = []
3491
3492 if errors:
3493 results.append(output_api.PresubmitError(
3494 'android.webkit.ValueCallback usage is detected outside of the glue'
3495 ' layer. To stay compatible with the support library, android.webkit.*'
3496 ' classes should only be used inside the glue layer and'
3497 ' org.chromium.base.Callback should be used instead.',
3498 errors))
3499
3500 return results
3501
3502
Becky Zhou7c69b50992018-12-10 19:37:573503def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3504 """Checks Android XML styles """
3505 import sys
3506 original_sys_path = sys.path
3507 try:
3508 sys.path = sys.path + [input_api.os_path.join(
3509 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3510 import checkxmlstyle
3511 finally:
3512 # Restore sys.path to what it was before.
3513 sys.path = original_sys_path
3514
3515 if is_check_on_upload:
3516 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3517 else:
3518 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3519
3520
agrievef32bcc72016-04-04 14:57:403521class PydepsChecker(object):
3522 def __init__(self, input_api, pydeps_files):
3523 self._file_cache = {}
3524 self._input_api = input_api
3525 self._pydeps_files = pydeps_files
3526
3527 def _LoadFile(self, path):
3528 """Returns the list of paths within a .pydeps file relative to //."""
3529 if path not in self._file_cache:
3530 with open(path) as f:
3531 self._file_cache[path] = f.read()
3532 return self._file_cache[path]
3533
3534 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3535 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393536 pydeps_data = self._LoadFile(pydeps_path)
3537 uses_gn_paths = '--gn-paths' in pydeps_data
3538 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3539 if uses_gn_paths:
3540 # Paths look like: //foo/bar/baz
3541 return (e[2:] for e in entries)
3542 else:
3543 # Paths look like: path/relative/to/file.pydeps
3544 os_path = self._input_api.os_path
3545 pydeps_dir = os_path.dirname(pydeps_path)
3546 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403547
3548 def _CreateFilesToPydepsMap(self):
3549 """Returns a map of local_path -> list_of_pydeps."""
3550 ret = {}
3551 for pydep_local_path in self._pydeps_files:
3552 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3553 ret.setdefault(path, []).append(pydep_local_path)
3554 return ret
3555
3556 def ComputeAffectedPydeps(self):
3557 """Returns an iterable of .pydeps files that might need regenerating."""
3558 affected_pydeps = set()
3559 file_to_pydeps_map = None
3560 for f in self._input_api.AffectedFiles(include_deletes=True):
3561 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463562 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3563 # subrepositories. We can't figure out which files change, so re-check
3564 # all files.
3565 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383566 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3567 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403568 return self._pydeps_files
3569 elif local_path.endswith('.pydeps'):
3570 if local_path in self._pydeps_files:
3571 affected_pydeps.add(local_path)
3572 elif local_path.endswith('.py'):
3573 if file_to_pydeps_map is None:
3574 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3575 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3576 return affected_pydeps
3577
3578 def DetermineIfStale(self, pydeps_path):
3579 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413580 import difflib
John Budorick47ca3fe2018-02-10 00:53:103581 import os
3582
agrievef32bcc72016-04-04 14:57:403583 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033584 if old_pydeps_data:
3585 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393586 if '--output' not in cmd:
3587 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033588 old_contents = old_pydeps_data[2:]
3589 else:
3590 # A default cmd that should work in most cases (as long as pydeps filename
3591 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3592 # file is empty/new.
3593 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3594 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3595 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103596 env = dict(os.environ)
3597 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403598 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103599 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413600 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033601 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413602 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403603
3604
Tibor Goldschwendt360793f72019-06-25 18:23:493605def _ParseGclientArgs():
3606 args = {}
3607 with open('build/config/gclient_args.gni', 'r') as f:
3608 for line in f:
3609 line = line.strip()
3610 if not line or line.startswith('#'):
3611 continue
3612 attribute, value = line.split('=')
3613 args[attribute.strip()] = value.strip()
3614 return args
3615
3616
Saagar Sanghavifceeaae2020-08-12 16:40:363617def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403618 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403619 # This check is for Python dependency lists (.pydeps files), and involves
3620 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3621 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283622 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003623 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493624 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403625 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403626 results = []
3627 # First, check for new / deleted .pydeps.
3628 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033629 # Check whether we are running the presubmit check for a file in src.
3630 # f.LocalPath is relative to repo (src, or internal repo).
3631 # os_path.exists is relative to src repo.
3632 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3633 # to src and we can conclude that the pydeps is in src.
3634 if input_api.os_path.exists(f.LocalPath()):
3635 if f.LocalPath().endswith('.pydeps'):
3636 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3637 results.append(output_api.PresubmitError(
3638 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3639 'remove %s' % f.LocalPath()))
3640 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3641 results.append(output_api.PresubmitError(
3642 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3643 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403644
3645 if results:
3646 return results
3647
Mohamed Heikal7cd4d8312020-06-16 16:49:403648 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3649 affected_pydeps = set(checker.ComputeAffectedPydeps())
3650 affected_android_pydeps = affected_pydeps.intersection(
3651 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3652 if affected_android_pydeps and not is_android:
3653 results.append(output_api.PresubmitPromptOrNotify(
3654 'You have changed python files that may affect pydeps for android\n'
3655 'specific scripts. However, the relevant presumbit check cannot be\n'
3656 'run because you are not using an Android checkout. To validate that\n'
3657 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3658 'use the android-internal-presubmit optional trybot.\n'
3659 'Possibly stale pydeps files:\n{}'.format(
3660 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403661
Mohamed Heikal7cd4d8312020-06-16 16:49:403662 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3663 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403664 try:
phajdan.jr0d9878552016-11-04 10:49:413665 result = checker.DetermineIfStale(pydep_path)
3666 if result:
3667 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403668 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413669 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3670 'To regenerate, run:\n\n %s' %
3671 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403672 except input_api.subprocess.CalledProcessError as error:
3673 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3674 long_text=error.output)]
3675
3676 return results
3677
3678
Saagar Sanghavifceeaae2020-08-12 16:40:363679def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433680 """Checks to make sure no header files have |Singleton<|."""
3681 def FileFilter(affected_file):
3682 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443683 files_to_skip = (_EXCLUDED_PATHS +
3684 input_api.DEFAULT_FILES_TO_SKIP +
3685 (r"^base[\\/]memory[\\/]singleton\.h$",
3686 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3687 r"quic_singleton_impl\.h$"))
3688 return input_api.FilterSourceFile(affected_file,
3689 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433690
sergeyu34d21222015-09-16 00:11:443691 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433692 files = []
3693 for f in input_api.AffectedSourceFiles(FileFilter):
3694 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3695 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3696 contents = input_api.ReadFile(f)
3697 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243698 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433699 pattern.search(line)):
3700 files.append(f)
3701 break
3702
3703 if files:
yolandyandaabc6d2016-04-18 18:29:393704 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443705 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433706 'Please move them to an appropriate source file so that the ' +
3707 'template gets instantiated in a single compilation unit.',
3708 files) ]
3709 return []
3710
3711
[email protected]fd20b902014-05-09 02:14:533712_DEPRECATED_CSS = [
3713 # Values
3714 ( "-webkit-box", "flex" ),
3715 ( "-webkit-inline-box", "inline-flex" ),
3716 ( "-webkit-flex", "flex" ),
3717 ( "-webkit-inline-flex", "inline-flex" ),
3718 ( "-webkit-min-content", "min-content" ),
3719 ( "-webkit-max-content", "max-content" ),
3720
3721 # Properties
3722 ( "-webkit-background-clip", "background-clip" ),
3723 ( "-webkit-background-origin", "background-origin" ),
3724 ( "-webkit-background-size", "background-size" ),
3725 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443726 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533727
3728 # Functions
3729 ( "-webkit-gradient", "gradient" ),
3730 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3731 ( "-webkit-linear-gradient", "linear-gradient" ),
3732 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3733 ( "-webkit-radial-gradient", "radial-gradient" ),
3734 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3735]
3736
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203737
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493738# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363739def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533740 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253741 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343742 documentation and iOS CSS for dom distiller
3743 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253744 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533745 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493746 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443747 files_to_skip = (_EXCLUDED_PATHS +
3748 _TEST_CODE_EXCLUDED_PATHS +
3749 input_api.DEFAULT_FILES_TO_SKIP +
3750 (r"^chrome/common/extensions/docs",
3751 r"^chrome/docs",
3752 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3753 r"^components/neterror/resources/neterror.css",
3754 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253755 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443756 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533757 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3758 for line_num, line in fpath.ChangedContents():
3759 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023760 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533761 results.append(output_api.PresubmitError(
3762 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3763 (fpath.LocalPath(), line_num, deprecated_value, value)))
3764 return results
3765
mohan.reddyf21db962014-10-16 12:26:473766
Saagar Sanghavifceeaae2020-08-12 16:40:363767def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363768 bad_files = {}
3769 for f in input_api.AffectedFiles(include_deletes=False):
3770 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493771 not f.LocalPath().startswith('third_party/blink') and
3772 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363773 continue
3774
Daniel Bratell65b033262019-04-23 08:17:063775 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363776 continue
3777
Vaclav Brozekd5de76a2018-03-17 07:57:503778 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363779 if "#include" in line and "../" in line]
3780 if not relative_includes:
3781 continue
3782 bad_files[f.LocalPath()] = relative_includes
3783
3784 if not bad_files:
3785 return []
3786
3787 error_descriptions = []
3788 for file_path, bad_lines in bad_files.iteritems():
3789 error_description = file_path
3790 for line in bad_lines:
3791 error_description += '\n ' + line
3792 error_descriptions.append(error_description)
3793
3794 results = []
3795 results.append(output_api.PresubmitError(
3796 'You added one or more relative #include paths (including "../").\n'
3797 'These shouldn\'t be used because they can be used to include headers\n'
3798 'from code that\'s not correctly specified as a dependency in the\n'
3799 'relevant BUILD.gn file(s).',
3800 error_descriptions))
3801
3802 return results
3803
Takeshi Yoshinoe387aa32017-08-02 13:16:133804
Saagar Sanghavifceeaae2020-08-12 16:40:363805def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063806 """Check that nobody tries to include a cc file. It's a relatively
3807 common error which results in duplicate symbols in object
3808 files. This may not always break the build until someone later gets
3809 very confusing linking errors."""
3810 results = []
3811 for f in input_api.AffectedFiles(include_deletes=False):
3812 # We let third_party code do whatever it wants
3813 if (f.LocalPath().startswith('third_party') and
3814 not f.LocalPath().startswith('third_party/blink') and
3815 not f.LocalPath().startswith('third_party\\blink')):
3816 continue
3817
3818 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3819 continue
3820
3821 for _, line in f.ChangedContents():
3822 if line.startswith('#include "'):
3823 included_file = line.split('"')[1]
3824 if _IsCPlusPlusFile(input_api, included_file):
3825 # The most common naming for external files with C++ code,
3826 # apart from standard headers, is to call them foo.inc, but
3827 # Chromium sometimes uses foo-inc.cc so allow that as well.
3828 if not included_file.endswith(('.h', '-inc.cc')):
3829 results.append(output_api.PresubmitError(
3830 'Only header files or .inc files should be included in other\n'
3831 'C++ files. Compiling the contents of a cc file more than once\n'
3832 'will cause duplicate information in the build which may later\n'
3833 'result in strange link_errors.\n' +
3834 f.LocalPath() + ':\n ' +
3835 line))
3836
3837 return results
3838
3839
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203840def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3841 if not isinstance(key, ast.Str):
3842 return 'Key at line %d must be a string literal' % key.lineno
3843 if not isinstance(value, ast.Dict):
3844 return 'Value at line %d must be a dict' % value.lineno
3845 if len(value.keys) != 1:
3846 return 'Dict at line %d must have single entry' % value.lineno
3847 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3848 return (
3849 'Entry at line %d must have a string literal \'filepath\' as key' %
3850 value.lineno)
3851 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133852
Takeshi Yoshinoe387aa32017-08-02 13:16:133853
Sergey Ulanov4af16052018-11-08 02:41:463854def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203855 if not isinstance(key, ast.Str):
3856 return 'Key at line %d must be a string literal' % key.lineno
3857 if not isinstance(value, ast.List):
3858 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463859 for element in value.elts:
3860 if not isinstance(element, ast.Str):
3861 return 'Watchlist elements on line %d is not a string' % key.lineno
3862 if not email_regex.match(element.s):
3863 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3864 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203865 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133866
Takeshi Yoshinoe387aa32017-08-02 13:16:133867
Sergey Ulanov4af16052018-11-08 02:41:463868def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203869 mismatch_template = (
3870 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3871 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133872
Sergey Ulanov4af16052018-11-08 02:41:463873 email_regex = input_api.re.compile(
3874 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3875
3876 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203877 i = 0
3878 last_key = ''
3879 while True:
3880 if i >= len(wd_dict.keys):
3881 if i >= len(w_dict.keys):
3882 return None
3883 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3884 elif i >= len(w_dict.keys):
3885 return (
3886 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133887
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203888 wd_key = wd_dict.keys[i]
3889 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133890
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203891 result = _CheckWatchlistDefinitionsEntrySyntax(
3892 wd_key, wd_dict.values[i], ast)
3893 if result is not None:
3894 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133895
Sergey Ulanov4af16052018-11-08 02:41:463896 result = _CheckWatchlistsEntrySyntax(
3897 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203898 if result is not None:
3899 return 'Bad entry in WATCHLISTS dict: %s' % result
3900
3901 if wd_key.s != w_key.s:
3902 return mismatch_template % (
3903 '%s at line %d' % (wd_key.s, wd_key.lineno),
3904 '%s at line %d' % (w_key.s, w_key.lineno))
3905
3906 if wd_key.s < last_key:
3907 return (
3908 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3909 (wd_key.lineno, w_key.lineno))
3910 last_key = wd_key.s
3911
3912 i = i + 1
3913
3914
Sergey Ulanov4af16052018-11-08 02:41:463915def _CheckWATCHLISTSSyntax(expression, input_api):
3916 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203917 if not isinstance(expression, ast.Expression):
3918 return 'WATCHLISTS file must contain a valid expression'
3919 dictionary = expression.body
3920 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3921 return 'WATCHLISTS file must have single dict with exactly two entries'
3922
3923 first_key = dictionary.keys[0]
3924 first_value = dictionary.values[0]
3925 second_key = dictionary.keys[1]
3926 second_value = dictionary.values[1]
3927
3928 if (not isinstance(first_key, ast.Str) or
3929 first_key.s != 'WATCHLIST_DEFINITIONS' or
3930 not isinstance(first_value, ast.Dict)):
3931 return (
3932 'The first entry of the dict in WATCHLISTS file must be '
3933 'WATCHLIST_DEFINITIONS dict')
3934
3935 if (not isinstance(second_key, ast.Str) or
3936 second_key.s != 'WATCHLISTS' or
3937 not isinstance(second_value, ast.Dict)):
3938 return (
3939 'The second entry of the dict in WATCHLISTS file must be '
3940 'WATCHLISTS dict')
3941
Sergey Ulanov4af16052018-11-08 02:41:463942 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133943
3944
Saagar Sanghavifceeaae2020-08-12 16:40:363945def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133946 for f in input_api.AffectedFiles(include_deletes=False):
3947 if f.LocalPath() == 'WATCHLISTS':
3948 contents = input_api.ReadFile(f, 'r')
3949
3950 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203951 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133952 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203953 # Get an AST tree for it and scan the tree for detailed style checking.
3954 expression = input_api.ast.parse(
3955 contents, filename='WATCHLISTS', mode='eval')
3956 except ValueError as e:
3957 return [output_api.PresubmitError(
3958 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3959 except SyntaxError as e:
3960 return [output_api.PresubmitError(
3961 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3962 except TypeError as e:
3963 return [output_api.PresubmitError(
3964 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133965
Sergey Ulanov4af16052018-11-08 02:41:463966 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203967 if result is not None:
3968 return [output_api.PresubmitError(result)]
3969 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133970
3971 return []
3972
3973
Andrew Grieve1b290e4a22020-11-24 20:07:013974def CheckGnGlobForward(input_api, output_api):
3975 """Checks that forward_variables_from(invoker, "*") follows best practices.
3976
3977 As documented at //build/docs/writing_gn_templates.md
3978 """
3979 def gn_files(f):
3980 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3981
3982 problems = []
3983 for f in input_api.AffectedSourceFiles(gn_files):
3984 for line_num, line in f.ChangedContents():
3985 if 'forward_variables_from(invoker, "*")' in line:
3986 problems.append(
3987 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3988 f.LocalPath(), line_num))
3989
3990 if problems:
3991 return [output_api.PresubmitPromptWarning(
3992 'forward_variables_from("*") without exclusions',
3993 items=sorted(problems),
3994 long_text=('The variables "visibilty" and "test_only" should be '
3995 'explicitly listed in forward_variables_from(). For more '
3996 'details, see:\n'
3997 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
3998 'build/docs/writing_gn_templates.md'
3999 '#Using-forward_variables_from'))]
4000 return []
4001
4002
Saagar Sanghavifceeaae2020-08-12 16:40:364003def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194004 """Checks that newly added header files have corresponding GN changes.
4005 Note that this is only a heuristic. To be precise, run script:
4006 build/check_gn_headers.py.
4007 """
4008
4009 def headers(f):
4010 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444011 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194012
4013 new_headers = []
4014 for f in input_api.AffectedSourceFiles(headers):
4015 if f.Action() != 'A':
4016 continue
4017 new_headers.append(f.LocalPath())
4018
4019 def gn_files(f):
James Cook24a504192020-07-23 00:08:444020 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194021
4022 all_gn_changed_contents = ''
4023 for f in input_api.AffectedSourceFiles(gn_files):
4024 for _, line in f.ChangedContents():
4025 all_gn_changed_contents += line
4026
4027 problems = []
4028 for header in new_headers:
4029 basename = input_api.os_path.basename(header)
4030 if basename not in all_gn_changed_contents:
4031 problems.append(header)
4032
4033 if problems:
4034 return [output_api.PresubmitPromptWarning(
4035 'Missing GN changes for new header files', items=sorted(problems),
4036 long_text='Please double check whether newly added header files need '
4037 'corresponding changes in gn or gni files.\nThis checking is only a '
4038 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4039 'Read https://crbug.com/661774 for more info.')]
4040 return []
4041
4042
Saagar Sanghavifceeaae2020-08-12 16:40:364043def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024044 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4045
4046 This assumes we won't intentionally reference one product from the other
4047 product.
4048 """
4049 all_problems = []
4050 test_cases = [{
4051 "filename_postfix": "google_chrome_strings.grd",
4052 "correct_name": "Chrome",
4053 "incorrect_name": "Chromium",
4054 }, {
4055 "filename_postfix": "chromium_strings.grd",
4056 "correct_name": "Chromium",
4057 "incorrect_name": "Chrome",
4058 }]
4059
4060 for test_case in test_cases:
4061 problems = []
4062 filename_filter = lambda x: x.LocalPath().endswith(
4063 test_case["filename_postfix"])
4064
4065 # Check each new line. Can yield false positives in multiline comments, but
4066 # easier than trying to parse the XML because messages can have nested
4067 # children, and associating message elements with affected lines is hard.
4068 for f in input_api.AffectedSourceFiles(filename_filter):
4069 for line_num, line in f.ChangedContents():
4070 if "<message" in line or "<!--" in line or "-->" in line:
4071 continue
4072 if test_case["incorrect_name"] in line:
4073 problems.append(
4074 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4075
4076 if problems:
4077 message = (
4078 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4079 % (test_case["correct_name"], test_case["correct_name"],
4080 test_case["incorrect_name"]))
4081 all_problems.append(
4082 output_api.PresubmitPromptWarning(message, items=problems))
4083
4084 return all_problems
4085
4086
Saagar Sanghavifceeaae2020-08-12 16:40:364087def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364088 """Avoid large files, especially binary files, in the repository since
4089 git doesn't scale well for those. They will be in everyone's repo
4090 clones forever, forever making Chromium slower to clone and work
4091 with."""
4092
4093 # Uploading files to cloud storage is not trivial so we don't want
4094 # to set the limit too low, but the upper limit for "normal" large
4095 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4096 # anything over 20 MB is exceptional.
4097 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4098
4099 too_large_files = []
4100 for f in input_api.AffectedFiles():
4101 # Check both added and modified files (but not deleted files).
4102 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384103 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364104 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4105 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4106
4107 if too_large_files:
4108 message = (
4109 'Do not commit large files to git since git scales badly for those.\n' +
4110 'Instead put the large files in cloud storage and use DEPS to\n' +
4111 'fetch them.\n' + '\n'.join(too_large_files)
4112 )
4113 return [output_api.PresubmitError(
4114 'Too large files found in commit', long_text=message + '\n')]
4115 else:
4116 return []
4117
Max Morozb47503b2019-08-08 21:03:274118
Saagar Sanghavifceeaae2020-08-12 16:40:364119def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274120 """Checks specific for fuzz target sources."""
4121 EXPORTED_SYMBOLS = [
4122 'LLVMFuzzerInitialize',
4123 'LLVMFuzzerCustomMutator',
4124 'LLVMFuzzerCustomCrossOver',
4125 'LLVMFuzzerMutate',
4126 ]
4127
4128 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4129
4130 def FilterFile(affected_file):
4131 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444132 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4133 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274134
4135 return input_api.FilterSourceFile(
4136 affected_file,
James Cook24a504192020-07-23 00:08:444137 files_to_check=[files_to_check],
4138 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274139
4140 files_with_missing_header = []
4141 for f in input_api.AffectedSourceFiles(FilterFile):
4142 contents = input_api.ReadFile(f, 'r')
4143 if REQUIRED_HEADER in contents:
4144 continue
4145
4146 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4147 files_with_missing_header.append(f.LocalPath())
4148
4149 if not files_with_missing_header:
4150 return []
4151
4152 long_text = (
4153 'If you define any of the libFuzzer optional functions (%s), it is '
4154 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4155 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4156 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4157 'to access command line arguments passed to the fuzzer. Instead, prefer '
4158 'static initialization and shared resources as documented in '
4159 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4160 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4161 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4162 )
4163
4164 return [output_api.PresubmitPromptWarning(
4165 message="Missing '%s' in:" % REQUIRED_HEADER,
4166 items=files_with_missing_header,
4167 long_text=long_text)]
4168
4169
Mohamed Heikald048240a2019-11-12 16:57:374170def _CheckNewImagesWarning(input_api, output_api):
4171 """
4172 Warns authors who add images into the repo to make sure their images are
4173 optimized before committing.
4174 """
4175 images_added = False
4176 image_paths = []
4177 errors = []
4178 filter_lambda = lambda x: input_api.FilterSourceFile(
4179 x,
James Cook24a504192020-07-23 00:08:444180 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4181 + input_api.DEFAULT_FILES_TO_SKIP),
4182 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374183 )
4184 for f in input_api.AffectedFiles(
4185 include_deletes=False, file_filter=filter_lambda):
4186 local_path = f.LocalPath().lower()
4187 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4188 images_added = True
4189 image_paths.append(f)
4190 if images_added:
4191 errors.append(output_api.PresubmitPromptWarning(
4192 'It looks like you are trying to commit some images. If these are '
4193 'non-test-only images, please make sure to read and apply the tips in '
4194 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4195 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4196 'FYI only and will not block your CL on the CQ.', image_paths))
4197 return errors
4198
4199
Saagar Sanghavifceeaae2020-08-12 16:40:364200def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574201 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224202 results = []
dgnaa68d5e2015-06-10 10:08:224203 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174204 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224205 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294206 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064207 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4208 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424209 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184210 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574211 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374212 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154213 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574214 return results
4215
Saagar Sanghavifceeaae2020-08-12 16:40:364216def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574217 """Groups commit checks that target android code."""
4218 results = []
4219 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224220 return results
4221
Chris Hall59f8d0c72020-05-01 07:31:194222# TODO(chrishall): could we additionally match on any path owned by
4223# ui/accessibility/OWNERS ?
4224_ACCESSIBILITY_PATHS = (
4225 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4226 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4227 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4228 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4229 r"^content[\\/]browser[\\/]accessibility[\\/]",
4230 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4231 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4232 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4233 r"^ui[\\/]accessibility[\\/]",
4234 r"^ui[\\/]views[\\/]accessibility[\\/]",
4235)
4236
Saagar Sanghavifceeaae2020-08-12 16:40:364237def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194238 """Checks that commits to accessibility code contain an AX-Relnotes field in
4239 their commit message."""
4240 def FileFilter(affected_file):
4241 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444242 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194243
4244 # Only consider changes affecting accessibility paths.
4245 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4246 return []
4247
Akihiro Ota08108e542020-05-20 15:30:534248 # AX-Relnotes can appear in either the description or the footer.
4249 # When searching the description, require 'AX-Relnotes:' to appear at the
4250 # beginning of a line.
4251 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4252 description_has_relnotes = any(ax_regex.match(line)
4253 for line in input_api.change.DescriptionText().lower().splitlines())
4254
4255 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4256 'AX-Relnotes', [])
4257 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194258 return []
4259
4260 # TODO(chrishall): link to Relnotes documentation in message.
4261 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4262 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4263 "user-facing changes"
4264 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4265 "user-facing effects"
4266 "\n if this is confusing or annoying then please contact members "
4267 "of ui/accessibility/OWNERS.")
4268
4269 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224270
seanmccullough4a9356252021-04-08 19:54:094271# string pattern, sequence of strings to show when pattern matches,
4272# error flag. True if match is a presubmit error, otherwise it's a warning.
4273_NON_INCLUSIVE_TERMS = (
4274 (
4275 # Note that \b pattern in python re is pretty particular. In this
4276 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4277 # ...' will not. This may require some tweaking to catch these cases
4278 # without triggering a lot of false positives. Leaving it naive and
4279 # less matchy for now.
4280 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4281 (
4282 'Please don\'t use blacklist, whitelist, ' # nocheck
4283 'or slave in your', # nocheck
4284 'code and make every effort to use other terms. Using "// nocheck"',
4285 '"# nocheck" or "<!-- nocheck -->"',
4286 'at the end of the offending line will bypass this PRESUBMIT error',
4287 'but avoid using this whenever possible. Reach out to',
4288 '[email protected] if you have questions'),
4289 True),)
4290
Saagar Sanghavifceeaae2020-08-12 16:40:364291def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394292 """Checks common to both upload and commit."""
4293 results = []
4294 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384295 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544296 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084297
4298 author = input_api.change.author_email
4299 if author and author not in _KNOWN_ROBOTS:
4300 results.extend(
4301 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4302
[email protected]9f919cc2013-07-31 03:04:044303 results.extend(
4304 input_api.canned_checks.CheckChangeHasNoTabs(
4305 input_api,
4306 output_api,
4307 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434308 results.extend(input_api.RunTests(
4309 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244310
Edward Lesmesce51df52020-08-04 22:10:174311 dirmd_bin = input_api.os_path.join(
4312 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4313 results.extend(input_api.RunTests(
4314 input_api.canned_checks.CheckDirMetadataFormat(
4315 input_api, output_api, dirmd_bin)))
4316 results.extend(
4317 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4318 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554319 results.extend(
4320 input_api.canned_checks.CheckNoNewMetadataInOwners(
4321 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094322 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4323 input_api, output_api,
4324 excluded_directories_relative_path = [
4325 'infra',
4326 'inclusive_language_presubmit_exempt_dirs.txt'
4327 ],
4328 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174329
Vaclav Brozekcdc7defb2018-03-20 09:54:354330 for f in input_api.AffectedFiles():
4331 path, name = input_api.os_path.split(f.LocalPath())
4332 if name == 'PRESUBMIT.py':
4333 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004334 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4335 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074336 # The PRESUBMIT.py file (and the directory containing it) might
4337 # have been affected by being moved or removed, so only try to
4338 # run the tests if they still exist.
4339 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4340 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444341 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394342 return results
[email protected]1f7b4172010-01-28 01:17:344343
[email protected]b337cb5b2011-01-23 21:24:054344
Saagar Sanghavifceeaae2020-08-12 16:40:364345def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494346 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4347 if f.LocalPath().endswith(('.orig', '.rej'))]
4348 if problems:
4349 return [output_api.PresubmitError(
4350 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034351 else:
4352 return []
[email protected]b8079ae4a2012-12-05 19:56:494353
4354
Saagar Sanghavifceeaae2020-08-12 16:40:364355def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214356 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4357 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4358 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074359 include_re = input_api.re.compile(
4360 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4361 extension_re = input_api.re.compile(r'\.[a-z]+$')
4362 errors = []
4363 for f in input_api.AffectedFiles():
4364 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4365 continue
4366 found_line_number = None
4367 found_macro = None
4368 for line_num, line in f.ChangedContents():
4369 match = macro_re.search(line)
4370 if match:
4371 found_line_number = line_num
4372 found_macro = match.group(2)
4373 break
4374 if not found_line_number:
4375 continue
4376
4377 found_include = False
4378 for line in f.NewContents():
4379 if include_re.search(line):
4380 found_include = True
4381 break
4382 if found_include:
4383 continue
4384
4385 if not f.LocalPath().endswith('.h'):
4386 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4387 try:
4388 content = input_api.ReadFile(primary_header_path, 'r')
4389 if include_re.search(content):
4390 continue
4391 except IOError:
4392 pass
4393 errors.append('%s:%d %s macro is used without including build/'
4394 'build_config.h.'
4395 % (f.LocalPath(), found_line_number, found_macro))
4396 if errors:
4397 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4398 return []
4399
4400
[email protected]b00342e7f2013-03-26 16:21:544401def _DidYouMeanOSMacro(bad_macro):
4402 try:
4403 return {'A': 'OS_ANDROID',
4404 'B': 'OS_BSD',
4405 'C': 'OS_CHROMEOS',
4406 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444407 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544408 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444409 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544410 'N': 'OS_NACL',
4411 'O': 'OS_OPENBSD',
4412 'P': 'OS_POSIX',
4413 'S': 'OS_SOLARIS',
4414 'W': 'OS_WIN'}[bad_macro[3].upper()]
4415 except KeyError:
4416 return ''
4417
4418
4419def _CheckForInvalidOSMacrosInFile(input_api, f):
4420 """Check for sensible looking, totally invalid OS macros."""
4421 preprocessor_statement = input_api.re.compile(r'^\s*#')
4422 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4423 results = []
4424 for lnum, line in f.ChangedContents():
4425 if preprocessor_statement.search(line):
4426 for match in os_macro.finditer(line):
4427 if not match.group(1) in _VALID_OS_MACROS:
4428 good = _DidYouMeanOSMacro(match.group(1))
4429 did_you_mean = ' (did you mean %s?)' % good if good else ''
4430 results.append(' %s:%d %s%s' % (f.LocalPath(),
4431 lnum,
4432 match.group(1),
4433 did_you_mean))
4434 return results
4435
4436
Saagar Sanghavifceeaae2020-08-12 16:40:364437def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544438 """Check all affected files for invalid OS macros."""
4439 bad_macros = []
tzik3f295992018-12-04 20:32:234440 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474441 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544442 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4443
4444 if not bad_macros:
4445 return []
4446
4447 return [output_api.PresubmitError(
4448 'Possibly invalid OS macro[s] found. Please fix your code\n'
4449 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4450
lliabraa35bab3932014-10-01 12:16:444451
4452def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4453 """Check all affected files for invalid "if defined" macros."""
4454 ALWAYS_DEFINED_MACROS = (
4455 "TARGET_CPU_PPC",
4456 "TARGET_CPU_PPC64",
4457 "TARGET_CPU_68K",
4458 "TARGET_CPU_X86",
4459 "TARGET_CPU_ARM",
4460 "TARGET_CPU_MIPS",
4461 "TARGET_CPU_SPARC",
4462 "TARGET_CPU_ALPHA",
4463 "TARGET_IPHONE_SIMULATOR",
4464 "TARGET_OS_EMBEDDED",
4465 "TARGET_OS_IPHONE",
4466 "TARGET_OS_MAC",
4467 "TARGET_OS_UNIX",
4468 "TARGET_OS_WIN32",
4469 )
4470 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4471 results = []
4472 for lnum, line in f.ChangedContents():
4473 for match in ifdef_macro.finditer(line):
4474 if match.group(1) in ALWAYS_DEFINED_MACROS:
4475 always_defined = ' %s is always defined. ' % match.group(1)
4476 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4477 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4478 lnum,
4479 always_defined,
4480 did_you_mean))
4481 return results
4482
4483
Saagar Sanghavifceeaae2020-08-12 16:40:364484def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444485 """Check all affected files for invalid "if defined" macros."""
4486 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054487 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444488 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054489 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214490 continue
lliabraa35bab3932014-10-01 12:16:444491 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4492 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4493
4494 if not bad_macros:
4495 return []
4496
4497 return [output_api.PresubmitError(
4498 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4499 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4500 bad_macros)]
4501
4502
Saagar Sanghavifceeaae2020-08-12 16:40:364503def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044504 """Check for same IPC rules described in
4505 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4506 """
4507 base_pattern = r'IPC_ENUM_TRAITS\('
4508 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4509 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4510
4511 problems = []
4512 for f in input_api.AffectedSourceFiles(None):
4513 local_path = f.LocalPath()
4514 if not local_path.endswith('.h'):
4515 continue
4516 for line_number, line in f.ChangedContents():
4517 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4518 problems.append(
4519 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4520
4521 if problems:
4522 return [output_api.PresubmitPromptWarning(
4523 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4524 else:
4525 return []
4526
[email protected]b00342e7f2013-03-26 16:21:544527
Saagar Sanghavifceeaae2020-08-12 16:40:364528def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054529 """Check to make sure no files being submitted have long paths.
4530 This causes issues on Windows.
4531 """
4532 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194533 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054534 local_path = f.LocalPath()
4535 # Windows has a path limit of 260 characters. Limit path length to 200 so
4536 # that we have some extra for the prefix on dev machines and the bots.
4537 if len(local_path) > 200:
4538 problems.append(local_path)
4539
4540 if problems:
4541 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4542 else:
4543 return []
4544
4545
Saagar Sanghavifceeaae2020-08-12 16:40:364546def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144547 """Check that header files have proper guards against multiple inclusion.
4548 If a file should not have such guards (and it probably should) then it
4549 should include the string "no-include-guard-because-multiply-included".
4550 """
Daniel Bratell6a75baef62018-06-04 10:04:454551 def is_chromium_header_file(f):
4552 # We only check header files under the control of the Chromium
4553 # project. That is, those outside third_party apart from
4554 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324555 # We also exclude *_message_generator.h headers as they use
4556 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454557 file_with_path = input_api.os_path.normpath(f.LocalPath())
4558 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324559 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454560 (not file_with_path.startswith('third_party') or
4561 file_with_path.startswith(
4562 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144563
4564 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344565 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144566
4567 errors = []
4568
Daniel Bratell6a75baef62018-06-04 10:04:454569 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144570 guard_name = None
4571 guard_line_number = None
4572 seen_guard_end = False
4573
4574 file_with_path = input_api.os_path.normpath(f.LocalPath())
4575 base_file_name = input_api.os_path.splitext(
4576 input_api.os_path.basename(file_with_path))[0]
4577 upper_base_file_name = base_file_name.upper()
4578
4579 expected_guard = replace_special_with_underscore(
4580 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144581
4582 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574583 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4584 # are too many (1000+) files with slight deviations from the
4585 # coding style. The most important part is that the include guard
4586 # is there, and that it's unique, not the name so this check is
4587 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144588 #
4589 # As code becomes more uniform, this could be made stricter.
4590
4591 guard_name_pattern_list = [
4592 # Anything with the right suffix (maybe with an extra _).
4593 r'\w+_H__?',
4594
Daniel Bratell39b5b062018-05-16 18:09:574595 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144596 r'\w+_h',
4597
4598 # Anything including the uppercase name of the file.
4599 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4600 upper_base_file_name)) + r'\w*',
4601 ]
4602 guard_name_pattern = '|'.join(guard_name_pattern_list)
4603 guard_pattern = input_api.re.compile(
4604 r'#ifndef\s+(' + guard_name_pattern + ')')
4605
4606 for line_number, line in enumerate(f.NewContents()):
4607 if 'no-include-guard-because-multiply-included' in line:
4608 guard_name = 'DUMMY' # To not trigger check outside the loop.
4609 break
4610
4611 if guard_name is None:
4612 match = guard_pattern.match(line)
4613 if match:
4614 guard_name = match.group(1)
4615 guard_line_number = line_number
4616
Daniel Bratell39b5b062018-05-16 18:09:574617 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454618 # don't match the chromium style guide, but new files should
4619 # get it right.
4620 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574621 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144622 errors.append(output_api.PresubmitPromptWarning(
4623 'Header using the wrong include guard name %s' % guard_name,
4624 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574625 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144626 else:
4627 # The line after #ifndef should have a #define of the same name.
4628 if line_number == guard_line_number + 1:
4629 expected_line = '#define %s' % guard_name
4630 if line != expected_line:
4631 errors.append(output_api.PresubmitPromptWarning(
4632 'Missing "%s" for include guard' % expected_line,
4633 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4634 'Expected: %r\nGot: %r' % (expected_line, line)))
4635
4636 if not seen_guard_end and line == '#endif // %s' % guard_name:
4637 seen_guard_end = True
4638 elif seen_guard_end:
4639 if line.strip() != '':
4640 errors.append(output_api.PresubmitPromptWarning(
4641 'Include guard %s not covering the whole file' % (
4642 guard_name), [f.LocalPath()]))
4643 break # Nothing else to check and enough to warn once.
4644
4645 if guard_name is None:
4646 errors.append(output_api.PresubmitPromptWarning(
4647 'Missing include guard %s' % expected_guard,
4648 [f.LocalPath()],
4649 'Missing include guard in %s\n'
4650 'Recommended name: %s\n'
4651 'This check can be disabled by having the string\n'
4652 'no-include-guard-because-multiply-included in the header.' %
4653 (f.LocalPath(), expected_guard)))
4654
4655 return errors
4656
4657
Saagar Sanghavifceeaae2020-08-12 16:40:364658def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234659 """Check source code and known ascii text files for Windows style line
4660 endings.
4661 """
earthdok1b5e0ee2015-03-10 15:19:104662 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234663
4664 file_inclusion_pattern = (
4665 known_text_files,
4666 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4667 )
4668
mostynbb639aca52015-01-07 20:31:234669 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534670 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444671 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534672 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504673 include_file = False
4674 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234675 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504676 include_file = True
4677 if include_file:
4678 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234679
4680 if problems:
4681 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4682 'these files to contain Windows style line endings?\n' +
4683 '\n'.join(problems))]
4684
4685 return []
4686
Jose Magana2b456f22021-03-09 23:26:404687def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4688 """Check source code for use of Chrome App technologies being
4689 deprecated.
4690 """
4691
4692 def _CheckForDeprecatedTech(input_api, output_api,
4693 detection_list, files_to_check = None, files_to_skip = None):
4694
4695 if (files_to_check or files_to_skip):
4696 source_file_filter = lambda f: input_api.FilterSourceFile(
4697 f, files_to_check=files_to_check,
4698 files_to_skip=files_to_skip)
4699 else:
4700 source_file_filter = None
4701
4702 problems = []
4703
4704 for f in input_api.AffectedSourceFiles(source_file_filter):
4705 if f.Action() == 'D':
4706 continue
4707 for _, line in f.ChangedContents():
4708 if any( detect in line for detect in detection_list ):
4709 problems.append(f.LocalPath())
4710
4711 return problems
4712
4713 # to avoid this presubmit script triggering warnings
4714 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4715
4716 problems =[]
4717
4718 # NMF: any files with extensions .nmf or NMF
4719 _NMF_FILES = r'\.(nmf|NMF)$'
4720 problems += _CheckForDeprecatedTech(input_api, output_api,
4721 detection_list = [''], # any change to the file will trigger warning
4722 files_to_check = [ r'.+%s' % _NMF_FILES ])
4723
4724 # MANIFEST: any manifest.json that in its diff includes "app":
4725 _MANIFEST_FILES = r'(manifest\.json)$'
4726 problems += _CheckForDeprecatedTech(input_api, output_api,
4727 detection_list = ['"app":'],
4728 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4729
4730 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4731 problems += _CheckForDeprecatedTech(input_api, output_api,
4732 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4733 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4734
4735 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4736 problems += _CheckForDeprecatedTech(input_api, output_api,
4737 detection_list = ['#include "ppapi','#include <ppapi'],
4738 files_to_check = (
4739 r'.+%s' % _HEADER_EXTENSIONS,
4740 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4741 files_to_skip = [r"^ppapi[\\/]"] )
4742
4743 # Chrome Apps: any JS/TS file that references an API in the list below.
4744 # This should include the list of Chrome Apps APIs that are not Chrome
4745 # Extensions APIs as documented in:
4746 # https://developer.chrome.com/docs/apps/migration/
4747 detection_list_chrome_apps = [
4748 'chrome.accessibilityFeatures',
4749 'chrome.alarms',
4750 'chrome.app.runtime',
4751 'chrome.app.window',
4752 'chrome.audio',
4753 'chrome.bluetooth',
4754 'chrome.bluetoothLowEnergy',
4755 'chrome.bluetoothSocket',
4756 'chrome.browser',
4757 'chrome.commands',
4758 'chrome.contextMenus',
4759 'chrome.documentScan',
4760 'chrome.events',
4761 'chrome.extensionTypes',
4762 'chrome.fileSystem',
4763 'chrome.fileSystemProvider',
4764 'chrome.gcm',
4765 'chrome.hid',
4766 'chrome.i18n',
4767 'chrome.identity',
4768 'chrome.idle',
4769 'chrome.instanceID',
4770 'chrome.mdns',
4771 'chrome.mediaGalleries',
4772 'chrome.networking.onc',
4773 'chrome.notifications',
4774 'chrome.permissions',
4775 'chrome.power',
4776 'chrome.printerProvider',
4777 'chrome.runtime',
4778 'chrome.serial',
4779 'chrome.sockets.tcp',
4780 'chrome.sockets.tcpServer',
4781 'chrome.sockets.udp',
4782 'chrome.storage',
4783 'chrome.syncFileSystem',
4784 'chrome.system.cpu',
4785 'chrome.system.display',
4786 'chrome.system.memory',
4787 'chrome.system.network',
4788 'chrome.system.storage',
4789 'chrome.tts',
4790 'chrome.types',
4791 'chrome.usb',
4792 'chrome.virtualKeyboard',
4793 'chrome.vpnProvider',
4794 'chrome.wallpaper'
4795 ]
4796 _JS_FILES = r'\.(js|ts)$'
4797 problems += _CheckForDeprecatedTech(input_api, output_api,
4798 detection_list = detection_list_chrome_apps,
4799 files_to_check = [ r'.+%s' % _JS_FILES ],
4800 files_to_skip = files_to_skip)
4801
4802 if problems:
4803 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4804 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4805 ' PNaCl, PPAPI). See this blog post for more details:\n'
4806 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4807 'and this documentation for options to replace these technologies:\n'
4808 'https://developer.chrome.com/docs/apps/migration/\n'+
4809 '\n'.join(problems))]
4810
4811 return []
4812
mostynbb639aca52015-01-07 20:31:234813
Saagar Sanghavifceeaae2020-08-12 16:40:364814def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134815 """Checks that all source files use SYSLOG properly."""
4816 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364817 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564818 for line_number, line in f.ChangedContents():
4819 if 'SYSLOG' in line:
4820 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4821
pastarmovj89f7ee12016-09-20 14:58:134822 if syslog_files:
4823 return [output_api.PresubmitPromptWarning(
4824 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4825 ' calls.\nFiles to check:\n', items=syslog_files)]
4826 return []
4827
4828
[email protected]1f7b4172010-01-28 01:17:344829def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364830 if input_api.version < [2, 0, 0]:
4831 return [output_api.PresubmitError("Your depot_tools is out of date. "
4832 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4833 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344834 results = []
scottmg39b29952014-12-08 18:31:284835 results.extend(
jam93a6ee792017-02-08 23:59:224836 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544837 return results
[email protected]ca8d1982009-02-19 16:33:124838
4839
[email protected]1bfb8322014-04-23 01:02:414840def GetTryServerMasterForBot(bot):
4841 """Returns the Try Server master for the given bot.
4842
[email protected]0bb112362014-07-26 04:38:324843 It tries to guess the master from the bot name, but may still fail
4844 and return None. There is no longer a default master.
4845 """
4846 # Potentially ambiguous bot names are listed explicitly.
4847 master_map = {
tandriie5587792016-07-14 00:34:504848 'chromium_presubmit': 'master.tryserver.chromium.linux',
4849 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414850 }
[email protected]0bb112362014-07-26 04:38:324851 master = master_map.get(bot)
4852 if not master:
wnwen4fbaab82016-05-25 12:54:364853 if 'android' in bot:
tandriie5587792016-07-14 00:34:504854 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364855 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504856 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324857 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504858 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324859 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504860 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324861 return master
[email protected]1bfb8322014-04-23 01:02:414862
4863
[email protected]ca8d1982009-02-19 16:33:124864def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364865 if input_api.version < [2, 0, 0]:
4866 return [output_api.PresubmitError("Your depot_tools is out of date. "
4867 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4868 "but your version is %d.%d.%d" % tuple(input_api.version))]
4869
[email protected]fe5f57c52009-06-05 14:25:544870 results = []
[email protected]fe5f57c52009-06-05 14:25:544871 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274872 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344873 input_api,
4874 output_api,
[email protected]2fdd1f362013-01-16 03:56:034875 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274876
jam93a6ee792017-02-08 23:59:224877 results.extend(
4878 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544879 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4880 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384881 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4882 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414883 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4884 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544885 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144886
4887
Saagar Sanghavifceeaae2020-08-12 16:40:364888def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264889 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024890 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4891 # footer is set to true.
4892 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264893 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024894 footer.lower()
4895 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264896 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024897
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144898 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264899 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144900 import sys
4901 from io import StringIO
4902
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144903 new_or_added_paths = set(f.LocalPath()
4904 for f in input_api.AffectedFiles()
4905 if (f.Action() == 'A' or f.Action() == 'M'))
4906 removed_paths = set(f.LocalPath()
4907 for f in input_api.AffectedFiles(include_deletes=True)
4908 if f.Action() == 'D')
4909
Andrew Grieve0e8790c2020-09-03 17:27:324910 affected_grds = [
4911 f for f in input_api.AffectedFiles()
4912 if f.LocalPath().endswith(('.grd', '.grdp'))
4913 ]
4914 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164915 if not affected_grds:
4916 return []
4917
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144918 affected_png_paths = [f.AbsoluteLocalPath()
4919 for f in input_api.AffectedFiles()
4920 if (f.LocalPath().endswith('.png'))]
4921
4922 # Check for screenshots. Developers can upload screenshots using
4923 # tools/translation/upload_screenshots.py which finds and uploads
4924 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4925 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4926 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4927 #
4928 # The logic here is as follows:
4929 #
4930 # - If the CL has a .png file under the screenshots directory for a grd
4931 # file, warn the developer. Actual images should never be checked into the
4932 # Chrome repo.
4933 #
4934 # - If the CL contains modified or new messages in grd files and doesn't
4935 # contain the corresponding .sha1 files, warn the developer to add images
4936 # and upload them via tools/translation/upload_screenshots.py.
4937 #
4938 # - If the CL contains modified or new messages in grd files and the
4939 # corresponding .sha1 files, everything looks good.
4940 #
4941 # - If the CL contains removed messages in grd files but the corresponding
4942 # .sha1 files aren't removed, warn the developer to remove them.
4943 unnecessary_screenshots = []
4944 missing_sha1 = []
4945 unnecessary_sha1_files = []
4946
Rainhard Findlingfc31844c52020-05-15 09:58:264947 # This checks verifies that the ICU syntax of messages this CL touched is
4948 # valid, and reports any found syntax errors.
4949 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4950 # without developers being aware of them. Later on, such ICU syntax errors
4951 # break message extraction for translation, hence would block Chromium
4952 # translations until they are fixed.
4953 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144954
4955 def _CheckScreenshotAdded(screenshots_dir, message_id):
4956 sha1_path = input_api.os_path.join(
4957 screenshots_dir, message_id + '.png.sha1')
4958 if sha1_path not in new_or_added_paths:
4959 missing_sha1.append(sha1_path)
4960
4961
4962 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4963 sha1_path = input_api.os_path.join(
4964 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034965 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144966 unnecessary_sha1_files.append(sha1_path)
4967
Rainhard Findlingfc31844c52020-05-15 09:58:264968
4969 def _ValidateIcuSyntax(text, level, signatures):
4970 """Validates ICU syntax of a text string.
4971
4972 Check if text looks similar to ICU and checks for ICU syntax correctness
4973 in this case. Reports various issues with ICU syntax and values of
4974 variants. Supports checking of nested messages. Accumulate information of
4975 each ICU messages found in the text for further checking.
4976
4977 Args:
4978 text: a string to check.
4979 level: a number of current nesting level.
4980 signatures: an accumulator, a list of tuple of (level, variable,
4981 kind, variants).
4982
4983 Returns:
4984 None if a string is not ICU or no issue detected.
4985 A tuple of (message, start index, end index) if an issue detected.
4986 """
4987 valid_types = {
4988 'plural': (frozenset(
4989 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4990 frozenset(['=1', 'other'])),
4991 'selectordinal': (frozenset(
4992 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4993 frozenset(['one', 'other'])),
4994 'select': (frozenset(), frozenset(['other'])),
4995 }
4996
4997 # Check if the message looks like an attempt to use ICU
4998 # plural. If yes - check if its syntax strictly matches ICU format.
4999 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5000 if not like:
5001 signatures.append((level, None, None, None))
5002 return
5003
5004 # Check for valid prefix and suffix
5005 m = re.match(
5006 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5007 r'(plural|selectordinal|select),\s*'
5008 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5009 if not m:
5010 return (('This message looks like an ICU plural, '
5011 'but does not follow ICU syntax.'), like.start(), like.end())
5012 starting, variable, kind, variant_pairs = m.groups()
5013 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5014 if depth:
5015 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5016 len(text))
5017 first = text[0]
5018 ending = text[last_pos:]
5019 if not starting:
5020 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5021 last_pos)
5022 if not ending or '}' not in ending:
5023 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5024 last_pos)
5025 elif first != '{':
5026 return (
5027 ('Invalid ICU format. Extra characters at the start of a complex '
5028 'message (go/icu-message-migration): "%s"') %
5029 starting, 0, len(starting))
5030 elif ending != '}':
5031 return (('Invalid ICU format. Extra characters at the end of a complex '
5032 'message (go/icu-message-migration): "%s"')
5033 % ending, last_pos - 1, len(text) - 1)
5034 if kind not in valid_types:
5035 return (('Unknown ICU message type %s. '
5036 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5037 known, required = valid_types[kind]
5038 defined_variants = set()
5039 for variant, variant_range, value, value_range in variants:
5040 start, end = variant_range
5041 if variant in defined_variants:
5042 return ('Variant "%s" is defined more than once' % variant,
5043 start, end)
5044 elif known and variant not in known:
5045 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5046 start, end)
5047 defined_variants.add(variant)
5048 # Check for nested structure
5049 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5050 if res:
5051 return (res[0], res[1] + value_range[0] + 1,
5052 res[2] + value_range[0] + 1)
5053 missing = required - defined_variants
5054 if missing:
5055 return ('Required variants missing: %s' % ', '.join(missing), 0,
5056 len(text))
5057 signatures.append((level, variable, kind, defined_variants))
5058
5059
5060 def _ParseIcuVariants(text, offset=0):
5061 """Parse variants part of ICU complex message.
5062
5063 Builds a tuple of variant names and values, as well as
5064 their offsets in the input string.
5065
5066 Args:
5067 text: a string to parse
5068 offset: additional offset to add to positions in the text to get correct
5069 position in the complete ICU string.
5070
5071 Returns:
5072 List of tuples, each tuple consist of four fields: variant name,
5073 variant name span (tuple of two integers), variant value, value
5074 span (tuple of two integers).
5075 """
5076 depth, start, end = 0, -1, -1
5077 variants = []
5078 key = None
5079 for idx, char in enumerate(text):
5080 if char == '{':
5081 if not depth:
5082 start = idx
5083 chunk = text[end + 1:start]
5084 key = chunk.strip()
5085 pos = offset + end + 1 + chunk.find(key)
5086 span = (pos, pos + len(key))
5087 depth += 1
5088 elif char == '}':
5089 if not depth:
5090 return variants, depth, offset + idx
5091 depth -= 1
5092 if not depth:
5093 end = idx
5094 variants.append((key, span, text[start:end + 1], (offset + start,
5095 offset + end + 1)))
5096 return variants, depth, offset + end + 1
5097
meacer8c0d3832019-12-26 21:46:165098 try:
5099 old_sys_path = sys.path
5100 sys.path = sys.path + [input_api.os_path.join(
5101 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5102 from helper import grd_helper
5103 finally:
5104 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145105
5106 for f in affected_grds:
5107 file_path = f.LocalPath()
5108 old_id_to_msg_map = {}
5109 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385110 # Note that this code doesn't check if the file has been deleted. This is
5111 # OK because it only uses the old and new file contents and doesn't load
5112 # the file via its path.
5113 # It's also possible that a file's content refers to a renamed or deleted
5114 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5115 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5116 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117 if file_path.endswith('.grdp'):
5118 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585119 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395120 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145121 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585122 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395123 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145124 else:
meacerff8a9b62019-12-10 19:43:585125 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145126 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585127 old_id_to_msg_map = grd_helper.GetGrdMessages(
5128 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585130 new_id_to_msg_map = grd_helper.GetGrdMessages(
5131 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132
Rainhard Findlingd8d04372020-08-13 13:30:095133 grd_name, ext = input_api.os_path.splitext(
5134 input_api.os_path.basename(file_path))
5135 screenshots_dir = input_api.os_path.join(
5136 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5137
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138 # Compute added, removed and modified message IDs.
5139 old_ids = set(old_id_to_msg_map)
5140 new_ids = set(new_id_to_msg_map)
5141 added_ids = new_ids - old_ids
5142 removed_ids = old_ids - new_ids
5143 modified_ids = set([])
5144 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355145 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095146 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5147 # The message content itself changed. Require an updated screenshot.
5148 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355149 elif old_id_to_msg_map[key].attrs['meaning'] != \
5150 new_id_to_msg_map[key].attrs['meaning']:
5151 # The message meaning changed. Ensure there is a screenshot for it.
5152 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5153 if sha1_path not in new_or_added_paths and not \
5154 input_api.os_path.exists(sha1_path):
5155 # There is neither a previous screenshot nor is a new one added now.
5156 # Require a screenshot.
5157 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158
Rainhard Findlingfc31844c52020-05-15 09:58:265159 if run_screenshot_check:
5160 # Check the screenshot directory for .png files. Warn if there is any.
5161 for png_path in affected_png_paths:
5162 if png_path.startswith(screenshots_dir):
5163 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145164
Rainhard Findlingfc31844c52020-05-15 09:58:265165 for added_id in added_ids:
5166 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145167
Rainhard Findlingfc31844c52020-05-15 09:58:265168 for modified_id in modified_ids:
5169 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145170
Rainhard Findlingfc31844c52020-05-15 09:58:265171 for removed_id in removed_ids:
5172 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5173
5174 # Check new and changed strings for ICU syntax errors.
5175 for key in added_ids.union(modified_ids):
5176 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5177 err = _ValidateIcuSyntax(msg, 0, [])
5178 if err is not None:
5179 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145180
5181 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265182 if run_screenshot_check:
5183 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005184 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265185 'Do not include actual screenshots in the changelist. Run '
5186 'tools/translate/upload_screenshots.py to upload them instead:',
5187 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145188
Rainhard Findlingfc31844c52020-05-15 09:58:265189 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005190 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265191 'You are adding or modifying UI strings.\n'
5192 'To ensure the best translations, take screenshots of the relevant UI '
5193 '(https://g.co/chrome/translation) and add these files to your '
5194 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145195
Rainhard Findlingfc31844c52020-05-15 09:58:265196 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005197 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265198 'You removed strings associated with these files. Remove:',
5199 sorted(unnecessary_sha1_files)))
5200 else:
5201 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5202 'screenshots check.'))
5203
5204 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075205 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265206 'ICU syntax errors were found in the following strings (problems or '
5207 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145208
5209 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125210
5211
Saagar Sanghavifceeaae2020-08-12 16:40:365212def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125213 repo_root=None,
5214 translation_expectations_path=None,
5215 grd_files=None):
5216 import sys
5217 affected_grds = [f for f in input_api.AffectedFiles()
5218 if (f.LocalPath().endswith('.grd') or
5219 f.LocalPath().endswith('.grdp'))]
5220 if not affected_grds:
5221 return []
5222
5223 try:
5224 old_sys_path = sys.path
5225 sys.path = sys.path + [
5226 input_api.os_path.join(
5227 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5228 from helper import git_helper
5229 from helper import translation_helper
5230 finally:
5231 sys.path = old_sys_path
5232
5233 # Check that translation expectations can be parsed and we can get a list of
5234 # translatable grd files. |repo_root| and |translation_expectations_path| are
5235 # only passed by tests.
5236 if not repo_root:
5237 repo_root = input_api.PresubmitLocalPath()
5238 if not translation_expectations_path:
5239 translation_expectations_path = input_api.os_path.join(
5240 repo_root, 'tools', 'gritsettings',
5241 'translation_expectations.pyl')
5242 if not grd_files:
5243 grd_files = git_helper.list_grds_in_repository(repo_root)
5244
dpapad8e21b472020-10-23 17:15:035245 # Ignore bogus grd files used only for testing
5246 # ui/webui/resoucres/tools/generate_grd.py.
5247 ignore_path = input_api.os_path.join(
5248 'ui', 'webui', 'resources', 'tools', 'tests')
5249 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5250
Mustafa Emre Acer51f2f742020-03-09 19:41:125251 try:
5252 translation_helper.get_translatable_grds(repo_root, grd_files,
5253 translation_expectations_path)
5254 except Exception as e:
5255 return [output_api.PresubmitNotifyResult(
5256 'Failed to get a list of translatable grd files. This happens when:\n'
5257 ' - One of the modified grd or grdp files cannot be parsed or\n'
5258 ' - %s is not updated.\n'
5259 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5260 return []
Ken Rockotc31f4832020-05-29 18:58:515261
5262
Saagar Sanghavifceeaae2020-08-12 16:40:365263def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515264 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095265 changed_mojoms = input_api.AffectedFiles(
5266 include_deletes=True,
5267 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515268 delta = []
5269 for mojom in changed_mojoms:
5270 old_contents = ''.join(mojom.OldContents()) or None
5271 new_contents = ''.join(mojom.NewContents()) or None
5272 delta.append({
5273 'filename': mojom.LocalPath(),
5274 'old': '\n'.join(mojom.OldContents()) or None,
5275 'new': '\n'.join(mojom.NewContents()) or None,
5276 })
5277
5278 process = input_api.subprocess.Popen(
5279 [input_api.python_executable,
5280 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5281 'public', 'tools', 'mojom',
5282 'check_stable_mojom_compatibility.py'),
5283 '--src-root', input_api.PresubmitLocalPath()],
5284 stdin=input_api.subprocess.PIPE,
5285 stdout=input_api.subprocess.PIPE,
5286 stderr=input_api.subprocess.PIPE,
5287 universal_newlines=True)
5288 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5289 if process.returncode:
5290 return [output_api.PresubmitError(
5291 'One or more [Stable] mojom definitions appears to have been changed '
5292 'in a way that is not backward-compatible.',
5293 long_text=error)]
5294 return []
Dominic Battre645d42342020-12-04 16:14:105295
5296def CheckDeprecationOfPreferences(input_api, output_api):
5297 """Removing a preference should come with a deprecation."""
5298
5299 def FilterFile(affected_file):
5300 """Accept only .cc files and the like."""
5301 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5302 files_to_skip = (_EXCLUDED_PATHS +
5303 _TEST_CODE_EXCLUDED_PATHS +
5304 input_api.DEFAULT_FILES_TO_SKIP)
5305 return input_api.FilterSourceFile(
5306 affected_file,
5307 files_to_check=file_inclusion_pattern,
5308 files_to_skip=files_to_skip)
5309
5310 def ModifiedLines(affected_file):
5311 """Returns a list of tuples (line number, line text) of added and removed
5312 lines.
5313
5314 Deleted lines share the same line number as the previous line.
5315
5316 This relies on the scm diff output describing each changed code section
5317 with a line of the form
5318
5319 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5320 """
5321 line_num = 0
5322 modified_lines = []
5323 for line in affected_file.GenerateScmDiff().splitlines():
5324 # Extract <new line num> of the patch fragment (see format above).
5325 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5326 if m:
5327 line_num = int(m.groups(1)[0])
5328 continue
5329 if ((line.startswith('+') and not line.startswith('++')) or
5330 (line.startswith('-') and not line.startswith('--'))):
5331 modified_lines.append((line_num, line))
5332
5333 if not line.startswith('-'):
5334 line_num += 1
5335 return modified_lines
5336
5337 def FindLineWith(lines, needle):
5338 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5339
5340 If 0 or >1 lines contain `needle`, -1 is returned.
5341 """
5342 matching_line_numbers = [
5343 # + 1 for 1-based counting of line numbers.
5344 i + 1 for i, line
5345 in enumerate(lines)
5346 if needle in line]
5347 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5348
5349 def ModifiedPrefMigration(affected_file):
5350 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5351 # Determine first and last lines of MigrateObsolete.*Pref functions.
5352 new_contents = affected_file.NewContents();
5353 range_1 = (
5354 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5355 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5356 range_2 = (
5357 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5358 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5359 if (-1 in range_1 + range_2):
5360 raise Exception(
5361 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5362
5363 # Check whether any of the modified lines are part of the
5364 # MigrateObsolete.*Pref functions.
5365 for line_nr, line in ModifiedLines(affected_file):
5366 if (range_1[0] <= line_nr <= range_1[1] or
5367 range_2[0] <= line_nr <= range_2[1]):
5368 return True
5369 return False
5370
5371 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5372 browser_prefs_file_pattern = input_api.re.compile(
5373 r'chrome/browser/prefs/browser_prefs.cc')
5374
5375 changes = input_api.AffectedFiles(include_deletes=True,
5376 file_filter=FilterFile)
5377 potential_problems = []
5378 for f in changes:
5379 for line in f.GenerateScmDiff().splitlines():
5380 # Check deleted lines for pref registrations.
5381 if (line.startswith('-') and not line.startswith('--') and
5382 register_pref_pattern.search(line)):
5383 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5384
5385 if browser_prefs_file_pattern.search(f.LocalPath()):
5386 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5387 # assume that they knew that they have to deprecate preferences and don't
5388 # warn.
5389 try:
5390 if ModifiedPrefMigration(f):
5391 return []
5392 except Exception as e:
5393 return [output_api.PresubmitError(str(e))]
5394
5395 if potential_problems:
5396 return [output_api.PresubmitPromptWarning(
5397 'Discovered possible removal of preference registrations.\n\n'
5398 'Please make sure to properly deprecate preferences by clearing their\n'
5399 'value for a couple of milestones before finally removing the code.\n'
5400 'Otherwise data may stay in the preferences files forever. See\n'
5401 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc for examples.\n'
5402 'This may be a false positive warning (e.g. if you move preference\n'
5403 'registrations to a different place).\n',
5404 potential_problems
5405 )]
5406 return []