blob: bcf152ddba18607e452f4254eafbd67539a3110b [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 ),
Robert Liao22f66a52021-04-10 00:57:521052 (
1053 'RoInitialize',
1054 (
Robert Liao48018922021-04-16 23:03:021055 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:521056 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1057 'instead. See http://crbug.com/1197722 for more information.'
1058 ),
1059 True,
Robert Liao48018922021-04-16 23:03:021060 (
1061 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$'
1062 ),
Robert Liao22f66a52021-04-10 00:57:521063 ),
[email protected]127f18ec2012-06-16 05:05:591064)
1065
Mario Sanchez Prada2472cab2019-09-18 10:58:311066# Format: Sequence of tuples containing:
1067# * String pattern or, if starting with a slash, a regular expression.
1068# * Sequence of strings to show when the pattern matches.
1069_DEPRECATED_MOJO_TYPES = (
1070 (
1071 r'/\bmojo::AssociatedBinding\b',
1072 (
1073 'mojo::AssociatedBinding<Interface> is deprecated.',
1074 'Use mojo::AssociatedReceiver<Interface> instead.',
1075 ),
1076 ),
1077 (
1078 r'/\bmojo::AssociatedBindingSet\b',
1079 (
1080 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1081 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1082 ),
1083 ),
1084 (
1085 r'/\bmojo::AssociatedInterfacePtr\b',
1086 (
1087 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1088 'Use mojo::AssociatedRemote<Interface> instead.',
1089 ),
1090 ),
1091 (
1092 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1093 (
1094 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1095 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1096 ),
1097 ),
1098 (
1099 r'/\bmojo::AssociatedInterfaceRequest\b',
1100 (
1101 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1102 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1103 ),
1104 ),
1105 (
1106 r'/\bmojo::Binding\b',
1107 (
1108 'mojo::Binding<Interface> is deprecated.',
1109 'Use mojo::Receiver<Interface> instead.',
1110 ),
1111 ),
1112 (
1113 r'/\bmojo::BindingSet\b',
1114 (
1115 'mojo::BindingSet<Interface> is deprecated.',
1116 'Use mojo::ReceiverSet<Interface> instead.',
1117 ),
1118 ),
1119 (
1120 r'/\bmojo::InterfacePtr\b',
1121 (
1122 'mojo::InterfacePtr<Interface> is deprecated.',
1123 'Use mojo::Remote<Interface> instead.',
1124 ),
1125 ),
1126 (
1127 r'/\bmojo::InterfacePtrInfo\b',
1128 (
1129 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1130 'Use mojo::PendingRemote<Interface> instead.',
1131 ),
1132 ),
1133 (
1134 r'/\bmojo::InterfaceRequest\b',
1135 (
1136 'mojo::InterfaceRequest<Interface> is deprecated.',
1137 'Use mojo::PendingReceiver<Interface> instead.',
1138 ),
1139 ),
1140 (
1141 r'/\bmojo::MakeRequest\b',
1142 (
1143 'mojo::MakeRequest is deprecated.',
1144 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1145 ),
1146 ),
1147 (
1148 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1149 (
1150 'mojo::MakeRequest is deprecated.',
1151 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181152 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311153 ),
1154 ),
1155 (
1156 r'/\bmojo::MakeStrongBinding\b',
1157 (
1158 'mojo::MakeStrongBinding is deprecated.',
1159 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1160 'mojo::MakeSelfOwnedReceiver() instead.',
1161 ),
1162 ),
1163 (
1164 r'/\bmojo::MakeStrongAssociatedBinding\b',
1165 (
1166 'mojo::MakeStrongAssociatedBinding is deprecated.',
1167 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1168 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1169 ),
1170 ),
1171 (
Gyuyoung Kim4952ba62020-07-07 07:33:441172 r'/\bmojo::StrongAssociatedBinding\b',
1173 (
1174 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1175 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1176 ),
1177 ),
1178 (
1179 r'/\bmojo::StrongBinding\b',
1180 (
1181 'mojo::StrongBinding<Interface> is deprecated.',
1182 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1183 ),
1184 ),
1185 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311186 r'/\bmojo::StrongAssociatedBindingSet\b',
1187 (
1188 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1189 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1190 ),
1191 ),
1192 (
1193 r'/\bmojo::StrongBindingSet\b',
1194 (
1195 'mojo::StrongBindingSet<Interface> is deprecated.',
1196 'Use mojo::UniqueReceiverSet<Interface> instead.',
1197 ),
1198 ),
1199)
wnwenbdc444e2016-05-25 13:44:151200
mlamouria82272622014-09-16 18:45:041201_IPC_ENUM_TRAITS_DEPRECATED = (
1202 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501203 'See http://www.chromium.org/Home/chromium-security/education/'
1204 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041205
Stephen Martinis97a394142018-06-07 23:06:051206_LONG_PATH_ERROR = (
1207 'Some files included in this CL have file names that are too long (> 200'
1208 ' characters). If committed, these files will cause issues on Windows. See'
1209 ' https://crbug.com/612667 for more details.'
1210)
1211
Shenghua Zhangbfaa38b82017-11-16 21:58:021212_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041213 r".*[\\/]BuildHooksAndroidImpl\.java",
1214 r".*[\\/]LicenseContentProvider\.java",
1215 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281216 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021217]
[email protected]127f18ec2012-06-16 05:05:591218
Mohamed Heikald048240a2019-11-12 16:57:371219# List of image extensions that are used as resources in chromium.
1220_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1221
Sean Kau46e29bc2017-08-28 16:31:161222# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401223_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041224 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401225 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041226 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1227 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041228 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431229 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161230]
1231
1232
[email protected]b00342e7f2013-03-26 16:21:541233_VALID_OS_MACROS = (
1234 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081235 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541236 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441237 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121238 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541239 'OS_BSD',
1240 'OS_CAT', # For testing.
1241 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041242 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541243 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371244 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541245 'OS_IOS',
1246 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441247 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541248 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211249 'OS_NACL_NONSFI',
1250 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121251 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541252 'OS_OPENBSD',
1253 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371254 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541255 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541256 'OS_WIN',
1257)
1258
1259
Andrew Grieveb773bad2020-06-05 18:00:381260# These are not checked on the public chromium-presubmit trybot.
1261# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041262# checkouts.
agrievef32bcc72016-04-04 14:57:401263_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381264 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381265]
1266
1267
1268_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041269 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361270 'base/android/jni_generator/jni_generator.pydeps',
1271 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361272 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041273 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361274 'build/android/gyp/aar.pydeps',
1275 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271276 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361277 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381278 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361279 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021280 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221281 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111282 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361283 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361284 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361285 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111286 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041287 'build/android/gyp/create_app_bundle_apks.pydeps',
1288 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361289 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121290 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091291 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221292 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001293 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361294 'build/android/gyp/desugar.pydeps',
1295 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421296 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041297 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361298 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361299 'build/android/gyp/filter_zip.pydeps',
1300 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361301 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361302 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581303 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361304 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141305 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261306 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011307 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041308 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361309 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361310 'build/android/gyp/merge_manifest.pydeps',
1311 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221312 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361313 'build/android/gyp/proguard.pydeps',
Mohamed Heikala9dd71a2021-04-15 15:39:271314 'build/android/gyp/resources_shrinker/shrinker.pydeps',
Peter Wen578730b2020-03-19 19:55:461315 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241316 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461318 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561319 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/incremental_install/generate_android_manifest.pydeps',
1321 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041322 'build/android/resource_sizes.pydeps',
1323 'build/android/test_runner.pydeps',
1324 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361325 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321327 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271328 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1329 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041330 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001331 'components/cronet/tools/generate_javadoc.pydeps',
1332 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381333 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001334 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381335 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041336 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181337 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041338 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421339 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1340 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131341 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501342 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061343 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221344 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401345]
1346
wnwenbdc444e2016-05-25 13:44:151347
agrievef32bcc72016-04-04 14:57:401348_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1349
1350
Eric Boren6fd2b932018-01-25 15:05:081351# Bypass the AUTHORS check for these accounts.
1352_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591353 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451354 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591355 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521356 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071357 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041358 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271359 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041360 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161361 for s in ('chromium-internal-autoroll',)
1362 ) | set('%[email protected]' % s
1363 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081364
1365
Daniel Bratell65b033262019-04-23 08:17:061366def _IsCPlusPlusFile(input_api, file_path):
1367 """Returns True if this file contains C++-like code (and not Python,
1368 Go, Java, MarkDown, ...)"""
1369
1370 ext = input_api.os_path.splitext(file_path)[1]
1371 # This list is compatible with CppChecker.IsCppFile but we should
1372 # consider adding ".c" to it. If we do that we can use this function
1373 # at more places in the code.
1374 return ext in (
1375 '.h',
1376 '.cc',
1377 '.cpp',
1378 '.m',
1379 '.mm',
1380 )
1381
1382def _IsCPlusPlusHeaderFile(input_api, file_path):
1383 return input_api.os_path.splitext(file_path)[1] == ".h"
1384
1385
1386def _IsJavaFile(input_api, file_path):
1387 return input_api.os_path.splitext(file_path)[1] == ".java"
1388
1389
1390def _IsProtoFile(input_api, file_path):
1391 return input_api.os_path.splitext(file_path)[1] == ".proto"
1392
Mohamed Heikal5e5b7922020-10-29 18:57:591393
1394def CheckNoUpstreamDepsOnClank(input_api, output_api):
1395 """Prevent additions of dependencies from the upstream repo on //clank."""
1396 # clank can depend on clank
1397 if input_api.change.RepositoryRoot().endswith('clank'):
1398 return []
1399 build_file_patterns = [
1400 r'(.+/)?BUILD\.gn',
1401 r'.+\.gni',
1402 ]
1403 excluded_files = [
1404 r'build[/\\]config[/\\]android[/\\]config\.gni'
1405 ]
1406 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1407
1408 error_message = 'Disallowed import on //clank in an upstream build file:'
1409
1410 def FilterFile(affected_file):
1411 return input_api.FilterSourceFile(
1412 affected_file,
1413 files_to_check=build_file_patterns,
1414 files_to_skip=excluded_files)
1415
1416 problems = []
1417 for f in input_api.AffectedSourceFiles(FilterFile):
1418 local_path = f.LocalPath()
1419 for line_number, line in f.ChangedContents():
1420 if (bad_pattern.search(line)):
1421 problems.append(
1422 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1423 if problems:
1424 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1425 else:
1426 return []
1427
1428
Saagar Sanghavifceeaae2020-08-12 16:40:361429def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191430 """Attempts to prevent use of functions intended only for testing in
1431 non-testing code. For now this is just a best-effort implementation
1432 that ignores header files and may have some false positives. A
1433 better implementation would probably need a proper C++ parser.
1434 """
1435 # We only scan .cc files and the like, as the declaration of
1436 # for-testing functions in header files are hard to distinguish from
1437 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491438 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191439
jochenc0d4808c2015-07-27 09:25:421440 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191441 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091442 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131443 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191444 exclusion_pattern = input_api.re.compile(
1445 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1446 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131447 # Avoid a false positive in this case, where the method name, the ::, and
1448 # the closing { are all on different lines due to line wrapping.
1449 # HelperClassForTesting::
1450 # HelperClassForTesting(
1451 # args)
1452 # : member(0) {}
1453 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191454
1455 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441456 files_to_skip = (_EXCLUDED_PATHS +
1457 _TEST_CODE_EXCLUDED_PATHS +
1458 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191459 return input_api.FilterSourceFile(
1460 affected_file,
James Cook24a504192020-07-23 00:08:441461 files_to_check=file_inclusion_pattern,
1462 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191463
1464 problems = []
1465 for f in input_api.AffectedSourceFiles(FilterFile):
1466 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131467 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241468 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031469 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461470 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131471 not exclusion_pattern.search(line) and
1472 not allowlist_pattern.search(line) and
1473 not in_method_defn):
[email protected]55459852011-08-10 15:17:191474 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031475 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131476 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191477
1478 if problems:
[email protected]f7051d52013-04-02 18:31:421479 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031480 else:
1481 return []
[email protected]55459852011-08-10 15:17:191482
1483
Saagar Sanghavifceeaae2020-08-12 16:40:361484def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231485 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591486 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231487 """
1488 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1489 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1490 name_pattern = r'ForTest(s|ing)?'
1491 # Describes an occurrence of "ForTest*" inside a // comment.
1492 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501493 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551494 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231495 # Catch calls.
1496 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1497 # Ignore definitions. (Comments are ignored separately.)
1498 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1499
1500 problems = []
1501 sources = lambda x: input_api.FilterSourceFile(
1502 x,
James Cook24a504192020-07-23 00:08:441503 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1504 + input_api.DEFAULT_FILES_TO_SKIP),
1505 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 )
1507 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1508 local_path = f.LocalPath()
1509 is_inside_javadoc = False
1510 for line_number, line in f.ChangedContents():
1511 if is_inside_javadoc and javadoc_end_re.search(line):
1512 is_inside_javadoc = False
1513 if not is_inside_javadoc and javadoc_start_re.search(line):
1514 is_inside_javadoc = True
1515 if is_inside_javadoc:
1516 continue
1517 if (inclusion_re.search(line) and
1518 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501519 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231520 not exclusion_re.search(line)):
1521 problems.append(
1522 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1523
1524 if problems:
1525 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1526 else:
1527 return []
1528
1529
Saagar Sanghavifceeaae2020-08-12 16:40:361530def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541531 """Checks to make sure no .h files include <iostream>."""
1532 files = []
1533 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1534 input_api.re.MULTILINE)
1535 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1536 if not f.LocalPath().endswith('.h'):
1537 continue
1538 contents = input_api.ReadFile(f)
1539 if pattern.search(contents):
1540 files.append(f)
1541
1542 if len(files):
yolandyandaabc6d2016-04-18 18:29:391543 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061544 'Do not #include <iostream> in header files, since it inserts static '
1545 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541546 '#include <ostream>. See http://crbug.com/94794',
1547 files) ]
1548 return []
1549
Danil Chapovalov3518f362018-08-11 16:13:431550def _CheckNoStrCatRedefines(input_api, output_api):
1551 """Checks no windows headers with StrCat redefined are included directly."""
1552 files = []
1553 pattern_deny = input_api.re.compile(
1554 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1555 input_api.re.MULTILINE)
1556 pattern_allow = input_api.re.compile(
1557 r'^#include\s"base/win/windows_defines.inc"',
1558 input_api.re.MULTILINE)
1559 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1560 contents = input_api.ReadFile(f)
1561 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1562 files.append(f.LocalPath())
1563
1564 if len(files):
1565 return [output_api.PresubmitError(
1566 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1567 'directly since they pollute code with StrCat macro. Instead, '
1568 'include matching header from base/win. See http://crbug.com/856536',
1569 files) ]
1570 return []
1571
[email protected]10689ca2011-09-02 02:31:541572
Saagar Sanghavifceeaae2020-08-12 16:40:361573def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521574 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181575 problems = []
1576 for f in input_api.AffectedFiles():
1577 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1578 continue
1579
1580 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041581 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181582 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1583
1584 if not problems:
1585 return []
1586 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1587 '\n'.join(problems))]
1588
Saagar Sanghavifceeaae2020-08-12 16:40:361589def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341590 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1591
1592 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1593 instead of DISABLED_. To filter false positives, reports are only generated
1594 if a corresponding MAYBE_ line exists.
1595 """
1596 problems = []
1597
1598 # The following two patterns are looked for in tandem - is a test labeled
1599 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1600 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1601 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1602
1603 # This is for the case that a test is disabled on all platforms.
1604 full_disable_pattern = input_api.re.compile(
1605 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1606 input_api.re.MULTILINE)
1607
Katie Df13948e2018-09-25 07:33:441608 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341609 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1610 continue
1611
1612 # Search for MABYE_, DISABLE_ pairs.
1613 disable_lines = {} # Maps of test name to line number.
1614 maybe_lines = {}
1615 for line_num, line in f.ChangedContents():
1616 disable_match = disable_pattern.search(line)
1617 if disable_match:
1618 disable_lines[disable_match.group(1)] = line_num
1619 maybe_match = maybe_pattern.search(line)
1620 if maybe_match:
1621 maybe_lines[maybe_match.group(1)] = line_num
1622
1623 # Search for DISABLE_ occurrences within a TEST() macro.
1624 disable_tests = set(disable_lines.keys())
1625 maybe_tests = set(maybe_lines.keys())
1626 for test in disable_tests.intersection(maybe_tests):
1627 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1628
1629 contents = input_api.ReadFile(f)
1630 full_disable_match = full_disable_pattern.search(contents)
1631 if full_disable_match:
1632 problems.append(' %s' % f.LocalPath())
1633
1634 if not problems:
1635 return []
1636 return [
1637 output_api.PresubmitPromptWarning(
1638 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1639 '\n'.join(problems))
1640 ]
1641
[email protected]72df4e782012-06-21 16:28:181642
Saagar Sanghavifceeaae2020-08-12 16:40:361643def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571644 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521645 errors = []
Hans Wennborg944479f2020-06-25 21:39:251646 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521647 input_api.re.MULTILINE)
1648 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1649 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1650 continue
1651 for lnum, line in f.ChangedContents():
1652 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171653 errors.append(output_api.PresubmitError(
1654 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571655 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171656 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521657 return errors
1658
1659
Weilun Shia487fad2020-10-28 00:10:341660# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1661# more reliable way. See
1662# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191663
wnwenbdc444e2016-05-25 13:44:151664
Saagar Sanghavifceeaae2020-08-12 16:40:361665def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391666 """Check that FlakyTest annotation is our own instead of the android one"""
1667 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1668 files = []
1669 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1670 if f.LocalPath().endswith('Test.java'):
1671 if pattern.search(input_api.ReadFile(f)):
1672 files.append(f)
1673 if len(files):
1674 return [output_api.PresubmitError(
1675 'Use org.chromium.base.test.util.FlakyTest instead of '
1676 'android.test.FlakyTest',
1677 files)]
1678 return []
mcasasb7440c282015-02-04 14:52:191679
wnwenbdc444e2016-05-25 13:44:151680
Saagar Sanghavifceeaae2020-08-12 16:40:361681def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441682 """Make sure .DEPS.git is never modified manually."""
1683 if any(f.LocalPath().endswith('.DEPS.git') for f in
1684 input_api.AffectedFiles()):
1685 return [output_api.PresubmitError(
1686 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1687 'automated system based on what\'s in DEPS and your changes will be\n'
1688 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501689 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1690 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441691 'for more information')]
1692 return []
1693
1694
Saagar Sanghavifceeaae2020-08-12 16:40:361695def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471696 """Checks that DEPS file deps are from allowed_hosts."""
1697 # Run only if DEPS file has been modified to annoy fewer bystanders.
1698 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1699 return []
1700 # Outsource work to gclient verify
1701 try:
John Budorickf20c0042019-04-25 23:23:401702 gclient_path = input_api.os_path.join(
1703 input_api.PresubmitLocalPath(),
1704 'third_party', 'depot_tools', 'gclient.py')
1705 input_api.subprocess.check_output(
1706 [input_api.python_executable, gclient_path, 'verify'],
1707 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471708 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201709 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471710 return [output_api.PresubmitError(
1711 'DEPS file must have only git dependencies.',
1712 long_text=error.output)]
1713
1714
Mario Sanchez Prada2472cab2019-09-18 10:58:311715def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1716 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591717 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311718
1719 Returns an string composed of the name of the file, the line number where the
1720 match has been found and the additional text passed as |message| in case the
1721 target type name matches the text inside the line passed as parameter.
1722 """
Peng Huang9c5949a02020-06-11 19:20:541723 result = []
1724
danakjd18e8892020-12-17 17:42:011725 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1726 return result
1727 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541728 return result
1729
Mario Sanchez Prada2472cab2019-09-18 10:58:311730 matched = False
1731 if type_name[0:1] == '/':
1732 regex = type_name[1:]
1733 if input_api.re.search(regex, line):
1734 matched = True
1735 elif type_name in line:
1736 matched = True
1737
Mario Sanchez Prada2472cab2019-09-18 10:58:311738 if matched:
1739 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1740 for message_line in message:
1741 result.append(' %s' % message_line)
1742
1743 return result
1744
1745
Saagar Sanghavifceeaae2020-08-12 16:40:361746def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591747 """Make sure that banned functions are not used."""
1748 warnings = []
1749 errors = []
1750
James Cook24a504192020-07-23 00:08:441751 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151752 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441753 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151754 if input_api.re.match(item, local_path):
1755 return True
1756 return False
1757
Peter K. Lee6c03ccff2019-07-15 14:40:051758 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541759 local_path = affected_file.LocalPath()
1760 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1761 return False
1762 basename = input_api.os_path.basename(local_path)
1763 if 'ios' in basename.split('_'):
1764 return True
1765 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1766 if sep and 'ios' in local_path.split(sep):
1767 return True
1768 return False
1769
wnwenbdc444e2016-05-25 13:44:151770 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311771 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1772 func_name, message)
1773 if problems:
wnwenbdc444e2016-05-25 13:44:151774 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311775 errors.extend(problems)
1776 else:
1777 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151778
Eric Stevensona9a980972017-09-23 00:04:411779 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1780 for f in input_api.AffectedFiles(file_filter=file_filter):
1781 for line_num, line in f.ChangedContents():
1782 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1783 CheckForMatch(f, line_num, line, func_name, message, error)
1784
[email protected]127f18ec2012-06-16 05:05:591785 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1786 for f in input_api.AffectedFiles(file_filter=file_filter):
1787 for line_num, line in f.ChangedContents():
1788 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151789 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591790
Peter K. Lee6c03ccff2019-07-15 14:40:051791 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541792 for line_num, line in f.ChangedContents():
1793 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1794 CheckForMatch(f, line_num, line, func_name, message, error)
1795
Peter K. Lee6c03ccff2019-07-15 14:40:051796 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1797 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1798 for line_num, line in f.ChangedContents():
1799 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1800 CheckForMatch(f, line_num, line, func_name, message, error)
1801
[email protected]127f18ec2012-06-16 05:05:591802 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1803 for f in input_api.AffectedFiles(file_filter=file_filter):
1804 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491805 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441806 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491807 continue
wnwenbdc444e2016-05-25 13:44:151808 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591809
1810 result = []
1811 if (warnings):
1812 result.append(output_api.PresubmitPromptWarning(
1813 'Banned functions were used.\n' + '\n'.join(warnings)))
1814 if (errors):
1815 result.append(output_api.PresubmitError(
1816 'Banned functions were used.\n' + '\n'.join(errors)))
1817 return result
1818
1819
Michael Thiessen44457642020-02-06 00:24:151820def _CheckAndroidNoBannedImports(input_api, output_api):
1821 """Make sure that banned java imports are not used."""
1822 errors = []
1823
1824 def IsException(path, exceptions):
1825 for exception in exceptions:
1826 if (path.startswith(exception)):
1827 return True
1828 return False
1829
1830 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1831 for f in input_api.AffectedFiles(file_filter=file_filter):
1832 for line_num, line in f.ChangedContents():
1833 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1834 if IsException(f.LocalPath(), exceptions):
1835 continue;
1836 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1837 'import ' + import_name, message)
1838 if problems:
1839 errors.extend(problems)
1840 result = []
1841 if (errors):
1842 result.append(output_api.PresubmitError(
1843 'Banned imports were used.\n' + '\n'.join(errors)))
1844 return result
1845
1846
Saagar Sanghavifceeaae2020-08-12 16:40:361847def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311848 """Make sure that old Mojo types are not used."""
1849 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571850 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311851
Mario Sanchez Pradaaab91382019-12-19 08:57:091852 # For any path that is not an "ok" or an "error" path, a warning will be
1853 # raised if deprecated mojo types are found.
1854 ok_paths = ['components/arc']
1855 error_paths = ['third_party/blink', 'content']
1856
Mario Sanchez Prada2472cab2019-09-18 10:58:311857 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1858 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571859 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091860 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311861 continue
1862
1863 for line_num, line in f.ChangedContents():
1864 for func_name, message in _DEPRECATED_MOJO_TYPES:
1865 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1866 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571867
Mario Sanchez Prada2472cab2019-09-18 10:58:311868 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091869 # Raise errors inside |error_paths| and warnings everywhere else.
1870 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571871 errors.extend(problems)
1872 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311873 warnings.extend(problems)
1874
1875 result = []
1876 if (warnings):
1877 result.append(output_api.PresubmitPromptWarning(
1878 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571879 if (errors):
1880 result.append(output_api.PresubmitError(
1881 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311882 return result
1883
1884
Saagar Sanghavifceeaae2020-08-12 16:40:361885def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061886 """Make sure that banned functions are not used."""
1887 files = []
1888 pattern = input_api.re.compile(r'^#pragma\s+once',
1889 input_api.re.MULTILINE)
1890 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1891 if not f.LocalPath().endswith('.h'):
1892 continue
1893 contents = input_api.ReadFile(f)
1894 if pattern.search(contents):
1895 files.append(f)
1896
1897 if files:
1898 return [output_api.PresubmitError(
1899 'Do not use #pragma once in header files.\n'
1900 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1901 files)]
1902 return []
1903
[email protected]127f18ec2012-06-16 05:05:591904
Saagar Sanghavifceeaae2020-08-12 16:40:361905def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121906 """Checks to make sure we don't introduce use of foo ? true : false."""
1907 problems = []
1908 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1909 for f in input_api.AffectedFiles():
1910 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1911 continue
1912
1913 for line_num, line in f.ChangedContents():
1914 if pattern.match(line):
1915 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1916
1917 if not problems:
1918 return []
1919 return [output_api.PresubmitPromptWarning(
1920 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1921 '\n'.join(problems))]
1922
1923
Saagar Sanghavifceeaae2020-08-12 16:40:361924def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281925 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181926 change. Breaking - rules is an error, breaking ! rules is a
1927 warning.
1928 """
mohan.reddyf21db962014-10-16 12:26:471929 import sys
[email protected]55f9f382012-07-31 11:02:181930 # We need to wait until we have an input_api object and use this
1931 # roundabout construct to import checkdeps because this file is
1932 # eval-ed and thus doesn't have __file__.
1933 original_sys_path = sys.path
1934 try:
1935 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471936 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181937 import checkdeps
[email protected]55f9f382012-07-31 11:02:181938 from rules import Rule
1939 finally:
1940 # Restore sys.path to what it was before.
1941 sys.path = original_sys_path
1942
1943 added_includes = []
rhalavati08acd232017-04-03 07:23:281944 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241945 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181946 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061947 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501948 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081949 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061950 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501951 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081952 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061953 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501954 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081955 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181956
[email protected]26385172013-05-09 23:11:351957 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181958
1959 error_descriptions = []
1960 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281961 error_subjects = set()
1962 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361963
[email protected]55f9f382012-07-31 11:02:181964 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1965 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081966 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181967 description_with_path = '%s\n %s' % (path, rule_description)
1968 if rule_type == Rule.DISALLOW:
1969 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281970 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181971 else:
1972 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281973 warning_subjects.add("#includes")
1974
1975 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1976 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081977 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281978 description_with_path = '%s\n %s' % (path, rule_description)
1979 if rule_type == Rule.DISALLOW:
1980 error_descriptions.append(description_with_path)
1981 error_subjects.add("imports")
1982 else:
1983 warning_descriptions.append(description_with_path)
1984 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181985
Jinsuk Kim5a092672017-10-24 22:42:241986 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021987 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081988 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241989 description_with_path = '%s\n %s' % (path, rule_description)
1990 if rule_type == Rule.DISALLOW:
1991 error_descriptions.append(description_with_path)
1992 error_subjects.add("imports")
1993 else:
1994 warning_descriptions.append(description_with_path)
1995 warning_subjects.add("imports")
1996
[email protected]55f9f382012-07-31 11:02:181997 results = []
1998 if error_descriptions:
1999 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282000 'You added one or more %s that violate checkdeps rules.'
2001 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182002 error_descriptions))
2003 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422004 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282005 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182006 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282007 '%s? See relevant DEPS file(s) for details and contacts.' %
2008 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182009 warning_descriptions))
2010 return results
2011
2012
Saagar Sanghavifceeaae2020-08-12 16:40:362013def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222014 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152015 if input_api.platform == 'win32':
2016 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292017 checkperms_tool = input_api.os_path.join(
2018 input_api.PresubmitLocalPath(),
2019 'tools', 'checkperms', 'checkperms.py')
2020 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472021 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392022 with input_api.CreateTemporaryFile() as file_list:
2023 for f in input_api.AffectedFiles():
2024 # checkperms.py file/directory arguments must be relative to the
2025 # repository.
2026 file_list.write(f.LocalPath() + '\n')
2027 file_list.close()
2028 args += ['--file-list', file_list.name]
2029 try:
2030 input_api.subprocess.check_output(args)
2031 return []
2032 except input_api.subprocess.CalledProcessError as error:
2033 return [output_api.PresubmitError(
2034 'checkperms.py failed:',
2035 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222036
2037
Saagar Sanghavifceeaae2020-08-12 16:40:362038def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492039 """Makes sure we don't include ui/aura/window_property.h
2040 in header files.
2041 """
2042 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2043 errors = []
2044 for f in input_api.AffectedFiles():
2045 if not f.LocalPath().endswith('.h'):
2046 continue
2047 for line_num, line in f.ChangedContents():
2048 if pattern.match(line):
2049 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2050
2051 results = []
2052 if errors:
2053 results.append(output_api.PresubmitError(
2054 'Header files should not include ui/aura/window_property.h', errors))
2055 return results
2056
2057
[email protected]70ca77752012-11-20 03:45:032058def _CheckForVersionControlConflictsInFile(input_api, f):
2059 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2060 errors = []
2061 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162062 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232063 # First-level headers in markdown look a lot like version control
2064 # conflict markers. http://daringfireball.net/projects/markdown/basics
2065 continue
[email protected]70ca77752012-11-20 03:45:032066 if pattern.match(line):
2067 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2068 return errors
2069
2070
Saagar Sanghavifceeaae2020-08-12 16:40:362071def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032072 """Usually this is not intentional and will cause a compile failure."""
2073 errors = []
2074 for f in input_api.AffectedFiles():
2075 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2076
2077 results = []
2078 if errors:
2079 results.append(output_api.PresubmitError(
2080 'Version control conflict markers found, please resolve.', errors))
2081 return results
2082
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202083
Saagar Sanghavifceeaae2020-08-12 16:40:362084def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162085 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2086 errors = []
2087 for f in input_api.AffectedFiles():
2088 for line_num, line in f.ChangedContents():
2089 if pattern.search(line):
2090 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2091
2092 results = []
2093 if errors:
2094 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502095 'Found Google support URL addressed by answer number. Please replace '
2096 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162097 return results
2098
[email protected]70ca77752012-11-20 03:45:032099
Saagar Sanghavifceeaae2020-08-12 16:40:362100def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442101 def FilterFile(affected_file):
2102 """Filter function for use with input_api.AffectedSourceFiles,
2103 below. This filters out everything except non-test files from
2104 top-level directories that generally speaking should not hard-code
2105 service URLs (e.g. src/android_webview/, src/content/ and others).
2106 """
2107 return input_api.FilterSourceFile(
2108 affected_file,
James Cook24a504192020-07-23 00:08:442109 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2110 files_to_skip=(_EXCLUDED_PATHS +
2111 _TEST_CODE_EXCLUDED_PATHS +
2112 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442113
reillyi38965732015-11-16 18:27:332114 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2115 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462116 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2117 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442118 problems = [] # items are (filename, line_number, line)
2119 for f in input_api.AffectedSourceFiles(FilterFile):
2120 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462121 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442122 problems.append((f.LocalPath(), line_num, line))
2123
2124 if problems:
[email protected]f7051d52013-04-02 18:31:422125 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442126 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582127 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442128 [' %s:%d: %s' % (
2129 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032130 else:
2131 return []
[email protected]06e6d0ff2012-12-11 01:36:442132
2133
Saagar Sanghavifceeaae2020-08-12 16:40:362134def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292135 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2136 def FileFilter(affected_file):
2137 """Includes directories known to be Chrome OS only."""
2138 return input_api.FilterSourceFile(
2139 affected_file,
James Cook24a504192020-07-23 00:08:442140 files_to_check=('^ash/',
2141 '^chromeos/', # Top-level src/chromeos.
2142 '/chromeos/', # Any path component.
2143 '^components/arc',
2144 '^components/exo'),
2145 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292146
2147 prefs = []
2148 priority_prefs = []
2149 for f in input_api.AffectedFiles(file_filter=FileFilter):
2150 for line_num, line in f.ChangedContents():
2151 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2152 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2153 prefs.append(' %s' % line)
2154 if input_api.re.search(
2155 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2156 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2157 priority_prefs.append(' %s' % line)
2158
2159 results = []
2160 if (prefs):
2161 results.append(output_api.PresubmitPromptWarning(
2162 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2163 'by browser sync settings. If these prefs should be controlled by OS '
2164 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2165 if (priority_prefs):
2166 results.append(output_api.PresubmitPromptWarning(
2167 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2168 'controlled by browser sync settings. If these prefs should be '
2169 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2170 'instead.\n' + '\n'.join(prefs)))
2171 return results
2172
2173
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492174# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362175def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272176 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312177 The native_client_sdk directory is excluded because it has auto-generated PNG
2178 files for documentation.
[email protected]d2530012013-01-25 16:39:272179 """
[email protected]d2530012013-01-25 16:39:272180 errors = []
James Cook24a504192020-07-23 00:08:442181 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2182 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312183 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442184 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312185 for f in input_api.AffectedFiles(include_deletes=False,
2186 file_filter=file_filter):
2187 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272188
2189 results = []
2190 if errors:
2191 results.append(output_api.PresubmitError(
2192 'The name of PNG files should not have abbreviations. \n'
2193 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2194 'Contact [email protected] if you have questions.', errors))
2195 return results
2196
2197
Daniel Cheng4dcdb6b2017-04-13 08:30:172198def _ExtractAddRulesFromParsedDeps(parsed_deps):
2199 """Extract the rules that add dependencies from a parsed DEPS file.
2200
2201 Args:
2202 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2203 add_rules = set()
2204 add_rules.update([
2205 rule[1:] for rule in parsed_deps.get('include_rules', [])
2206 if rule.startswith('+') or rule.startswith('!')
2207 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502208 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172209 {}).iteritems():
2210 add_rules.update([
2211 rule[1:] for rule in rules
2212 if rule.startswith('+') or rule.startswith('!')
2213 ])
2214 return add_rules
2215
2216
2217def _ParseDeps(contents):
2218 """Simple helper for parsing DEPS files."""
2219 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172220 class _VarImpl:
2221
2222 def __init__(self, local_scope):
2223 self._local_scope = local_scope
2224
2225 def Lookup(self, var_name):
2226 """Implements the Var syntax."""
2227 try:
2228 return self._local_scope['vars'][var_name]
2229 except KeyError:
2230 raise Exception('Var is not defined: %s' % var_name)
2231
2232 local_scope = {}
2233 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172234 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592235 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172236 }
2237 exec contents in global_scope, local_scope
2238 return local_scope
2239
2240
2241def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592242 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412243 a set of DEPS entries that we should look up.
2244
2245 For a directory (rather than a specific filename) we fake a path to
2246 a specific filename by adding /DEPS. This is chosen as a file that
2247 will seldom or never be subject to per-file include_rules.
2248 """
[email protected]2b438d62013-11-14 17:54:142249 # We ignore deps entries on auto-generated directories.
2250 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082251
Daniel Cheng4dcdb6b2017-04-13 08:30:172252 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2253 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2254
2255 added_deps = new_deps.difference(old_deps)
2256
[email protected]2b438d62013-11-14 17:54:142257 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172258 for added_dep in added_deps:
2259 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2260 continue
2261 # Assume that a rule that ends in .h is a rule for a specific file.
2262 if added_dep.endswith('.h'):
2263 results.add(added_dep)
2264 else:
2265 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082266 return results
2267
2268
Saagar Sanghavifceeaae2020-08-12 16:40:362269def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552270 """When a dependency prefixed with + is added to a DEPS file, we
2271 want to make sure that the change is reviewed by an OWNER of the
2272 target file or directory, to avoid layering violations from being
2273 introduced. This check verifies that this happens.
2274 """
Joey Mou57048132021-02-26 22:17:552275 # We rely on Gerrit's code-owners to check approvals.
2276 # input_api.gerrit is always set for Chromium, but other projects
2277 # might not use Gerrit.
2278 if not input_api.gerrit:
2279 return []
Edward Lesmes44feb2332021-03-19 01:27:522280 if (input_api.change.issue and
2281 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232282 # Skip OWNERS check when Owners-Override label is approved. This is intended
2283 # for global owners, trusted bots, and on-call sheriffs. Review is still
2284 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522285 return []
Edward Lesmes6fba51082021-01-20 04:20:232286
Daniel Cheng4dcdb6b2017-04-13 08:30:172287 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242288
2289 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492290 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242291 for f in input_api.AffectedFiles(include_deletes=False,
2292 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552293 filename = input_api.os_path.basename(f.LocalPath())
2294 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172295 virtual_depended_on_files.update(_CalculateAddedDeps(
2296 input_api.os_path,
2297 '\n'.join(f.OldContents()),
2298 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552299
[email protected]e871964c2013-05-13 14:14:552300 if not virtual_depended_on_files:
2301 return []
2302
2303 if input_api.is_committing:
2304 if input_api.tbr:
2305 return [output_api.PresubmitNotifyResult(
2306 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272307 if input_api.dry_run:
2308 return [output_api.PresubmitNotifyResult(
2309 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552310 if not input_api.change.issue:
2311 return [output_api.PresubmitError(
2312 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402313 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552314 output = output_api.PresubmitError
2315 else:
2316 output = output_api.PresubmitNotifyResult
2317
tandriied3b7e12016-05-12 14:38:502318 owner_email, reviewers = (
2319 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2320 input_api,
Edward Lesmesa3846442021-02-08 20:20:032321 None,
tandriied3b7e12016-05-12 14:38:502322 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552323
2324 owner_email = owner_email or input_api.change.author_email
2325
Edward Lesmesa3846442021-02-08 20:20:032326 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2327 virtual_depended_on_files, reviewers.union([owner_email]), [])
2328 missing_files = [
2329 f for f in virtual_depended_on_files
2330 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412331
2332 # We strip the /DEPS part that was added by
2333 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2334 # directory.
2335 def StripDeps(path):
2336 start_deps = path.rfind('/DEPS')
2337 if start_deps != -1:
2338 return path[:start_deps]
2339 else:
2340 return path
2341 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552342 for path in missing_files]
2343
2344 if unapproved_dependencies:
2345 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152346 output('You need LGTM from owners of depends-on paths in DEPS that were '
2347 'modified in this CL:\n %s' %
2348 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032349 suggested_owners = input_api.owners_client.SuggestOwners(
2350 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152351 output_list.append(output(
2352 'Suggested missing target path OWNERS:\n %s' %
2353 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552354 return output_list
2355
2356 return []
2357
2358
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492359# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362360def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492361 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442362 files_to_skip = (_EXCLUDED_PATHS +
2363 _TEST_CODE_EXCLUDED_PATHS +
2364 input_api.DEFAULT_FILES_TO_SKIP +
2365 (r"^base[\\/]logging\.h$",
2366 r"^base[\\/]logging\.cc$",
2367 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2368 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2369 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2370 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2371 r"startup_browser_creator\.cc$",
2372 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2373 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2374 r"diagnostics_writer\.cc$",
2375 r"^chrome[\\/]chrome_cleaner[\\/].*",
2376 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2377 r"dll_hash_main\.cc$",
2378 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2379 r"^chromecast[\\/]",
2380 r"^cloud_print[\\/]",
2381 r"^components[\\/]browser_watcher[\\/]"
2382 r"dump_stability_report_main_win.cc$",
2383 r"^components[\\/]media_control[\\/]renderer[\\/]"
2384 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352385 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2386 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442387 r"^components[\\/]zucchini[\\/].*",
2388 # TODO(peter): Remove exception. https://crbug.com/534537
2389 r"^content[\\/]browser[\\/]notifications[\\/]"
2390 r"notification_event_dispatcher_impl\.cc$",
2391 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2392 r"gl_helper_benchmark\.cc$",
2393 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2394 r"^courgette[\\/]courgette_tool\.cc$",
2395 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2396 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2397 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082398 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542399 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2400 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442401 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2402 r"^ipc[\\/]ipc_logging\.cc$",
2403 r"^native_client_sdk[\\/]",
2404 r"^remoting[\\/]base[\\/]logging\.h$",
2405 r"^remoting[\\/]host[\\/].*",
2406 r"^sandbox[\\/]linux[\\/].*",
2407 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2408 r"dump_file_system.cc$",
2409 r"^tools[\\/]",
2410 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2411 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2412 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2413 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2414 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402415 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442416 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402417
thomasanderson625d3932017-03-29 07:16:582418 log_info = set([])
2419 printf = set([])
[email protected]85218562013-11-22 07:41:402420
2421 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582422 for _, line in f.ChangedContents():
2423 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2424 log_info.add(f.LocalPath())
2425 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2426 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372427
thomasanderson625d3932017-03-29 07:16:582428 if input_api.re.search(r"\bprintf\(", line):
2429 printf.add(f.LocalPath())
2430 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2431 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402432
2433 if log_info:
2434 return [output_api.PresubmitError(
2435 'These files spam the console log with LOG(INFO):',
2436 items=log_info)]
2437 if printf:
2438 return [output_api.PresubmitError(
2439 'These files spam the console log with printf/fprintf:',
2440 items=printf)]
2441 return []
2442
2443
Saagar Sanghavifceeaae2020-08-12 16:40:362444def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162445 """These types are all expected to hold locks while in scope and
2446 so should never be anonymous (which causes them to be immediately
2447 destroyed)."""
2448 they_who_must_be_named = [
2449 'base::AutoLock',
2450 'base::AutoReset',
2451 'base::AutoUnlock',
2452 'SkAutoAlphaRestore',
2453 'SkAutoBitmapShaderInstall',
2454 'SkAutoBlitterChoose',
2455 'SkAutoBounderCommit',
2456 'SkAutoCallProc',
2457 'SkAutoCanvasRestore',
2458 'SkAutoCommentBlock',
2459 'SkAutoDescriptor',
2460 'SkAutoDisableDirectionCheck',
2461 'SkAutoDisableOvalCheck',
2462 'SkAutoFree',
2463 'SkAutoGlyphCache',
2464 'SkAutoHDC',
2465 'SkAutoLockColors',
2466 'SkAutoLockPixels',
2467 'SkAutoMalloc',
2468 'SkAutoMaskFreeImage',
2469 'SkAutoMutexAcquire',
2470 'SkAutoPathBoundsUpdate',
2471 'SkAutoPDFRelease',
2472 'SkAutoRasterClipValidate',
2473 'SkAutoRef',
2474 'SkAutoTime',
2475 'SkAutoTrace',
2476 'SkAutoUnref',
2477 ]
2478 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2479 # bad: base::AutoLock(lock.get());
2480 # not bad: base::AutoLock lock(lock.get());
2481 bad_pattern = input_api.re.compile(anonymous)
2482 # good: new base::AutoLock(lock.get())
2483 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2484 errors = []
2485
2486 for f in input_api.AffectedFiles():
2487 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2488 continue
2489 for linenum, line in f.ChangedContents():
2490 if bad_pattern.search(line) and not good_pattern.search(line):
2491 errors.append('%s:%d' % (f.LocalPath(), linenum))
2492
2493 if errors:
2494 return [output_api.PresubmitError(
2495 'These lines create anonymous variables that need to be named:',
2496 items=errors)]
2497 return []
2498
2499
Saagar Sanghavifceeaae2020-08-12 16:40:362500def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532501 # Returns whether |template_str| is of the form <T, U...> for some types T
2502 # and U. Assumes that |template_str| is already in the form <...>.
2503 def HasMoreThanOneArg(template_str):
2504 # Level of <...> nesting.
2505 nesting = 0
2506 for c in template_str:
2507 if c == '<':
2508 nesting += 1
2509 elif c == '>':
2510 nesting -= 1
2511 elif c == ',' and nesting == 1:
2512 return True
2513 return False
2514
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492515 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102516 sources = lambda affected_file: input_api.FilterSourceFile(
2517 affected_file,
James Cook24a504192020-07-23 00:08:442518 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2519 input_api.DEFAULT_FILES_TO_SKIP),
2520 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552521
2522 # Pattern to capture a single "<...>" block of template arguments. It can
2523 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2524 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2525 # latter would likely require counting that < and > match, which is not
2526 # expressible in regular languages. Should the need arise, one can introduce
2527 # limited counting (matching up to a total number of nesting depth), which
2528 # should cover all practical cases for already a low nesting limit.
2529 template_arg_pattern = (
2530 r'<[^>]*' # Opening block of <.
2531 r'>([^<]*>)?') # Closing block of >.
2532 # Prefix expressing that whatever follows is not already inside a <...>
2533 # block.
2534 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102535 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552536 not_inside_template_arg_pattern
2537 + r'\bstd::unique_ptr'
2538 + template_arg_pattern
2539 + r'\(\)')
2540
2541 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2542 template_arg_no_array_pattern = (
2543 r'<[^>]*[^]]' # Opening block of <.
2544 r'>([^(<]*[^]]>)?') # Closing block of >.
2545 # Prefix saying that what follows is the start of an expression.
2546 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2547 # Suffix saying that what follows are call parentheses with a non-empty list
2548 # of arguments.
2549 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532550 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552551 return_construct_pattern = input_api.re.compile(
2552 start_of_expr_pattern
2553 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532554 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552555 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532556 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552557 + nonempty_arg_list_pattern)
2558
Vaclav Brozek851d9602018-04-04 16:13:052559 problems_constructor = []
2560 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102561 for f in input_api.AffectedSourceFiles(sources):
2562 for line_number, line in f.ChangedContents():
2563 # Disallow:
2564 # return std::unique_ptr<T>(foo);
2565 # bar = std::unique_ptr<T>(foo);
2566 # But allow:
2567 # return std::unique_ptr<T[]>(foo);
2568 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532569 # And also allow cases when the second template argument is present. Those
2570 # cases cannot be handled by std::make_unique:
2571 # return std::unique_ptr<T, U>(foo);
2572 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052573 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532574 return_construct_result = return_construct_pattern.search(line)
2575 if return_construct_result and not HasMoreThanOneArg(
2576 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052577 problems_constructor.append(
2578 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102579 # Disallow:
2580 # std::unique_ptr<T>()
2581 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052582 problems_nullptr.append(
2583 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2584
2585 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162586 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052587 errors.append(output_api.PresubmitError(
2588 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162589 problems_nullptr))
2590 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052591 errors.append(output_api.PresubmitError(
2592 'The following files use explicit std::unique_ptr constructor.'
2593 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162594 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102595 return errors
2596
2597
Saagar Sanghavifceeaae2020-08-12 16:40:362598def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082599 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522600 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082601 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522602 # If actions.xml is already included in the changelist, the PRESUBMIT
2603 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082604 return []
2605
Alexei Svitkine64505a92021-03-11 22:00:542606 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2607 files_to_skip = (_EXCLUDED_PATHS +
2608 _TEST_CODE_EXCLUDED_PATHS +
2609 input_api.DEFAULT_FILES_TO_SKIP )
2610 file_filter = lambda f: input_api.FilterSourceFile(
2611 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2612
[email protected]999261d2014-03-03 20:08:082613 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522614 current_actions = None
[email protected]999261d2014-03-03 20:08:082615 for f in input_api.AffectedFiles(file_filter=file_filter):
2616 for line_num, line in f.ChangedContents():
2617 match = input_api.re.search(action_re, line)
2618 if match:
[email protected]2f92dec2014-03-07 19:21:522619 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2620 # loaded only once.
2621 if not current_actions:
2622 with open('tools/metrics/actions/actions.xml') as actions_f:
2623 current_actions = actions_f.read()
2624 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082625 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522626 action = 'name="{0}"'.format(action_name)
2627 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082628 return [output_api.PresubmitPromptWarning(
2629 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522630 'tools/metrics/actions/actions.xml. Please run '
2631 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082632 % (f.LocalPath(), line_num, action_name))]
2633 return []
2634
2635
Daniel Cheng13ca61a882017-08-25 15:11:252636def _ImportJSONCommentEater(input_api):
2637 import sys
2638 sys.path = sys.path + [input_api.os_path.join(
2639 input_api.PresubmitLocalPath(),
2640 'tools', 'json_comment_eater')]
2641 import json_comment_eater
2642 return json_comment_eater
2643
2644
[email protected]99171a92014-06-03 08:44:472645def _GetJSONParseError(input_api, filename, eat_comments=True):
2646 try:
2647 contents = input_api.ReadFile(filename)
2648 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252649 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132650 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472651
2652 input_api.json.loads(contents)
2653 except ValueError as e:
2654 return e
2655 return None
2656
2657
2658def _GetIDLParseError(input_api, filename):
2659 try:
2660 contents = input_api.ReadFile(filename)
2661 idl_schema = input_api.os_path.join(
2662 input_api.PresubmitLocalPath(),
2663 'tools', 'json_schema_compiler', 'idl_schema.py')
2664 process = input_api.subprocess.Popen(
2665 [input_api.python_executable, idl_schema],
2666 stdin=input_api.subprocess.PIPE,
2667 stdout=input_api.subprocess.PIPE,
2668 stderr=input_api.subprocess.PIPE,
2669 universal_newlines=True)
2670 (_, error) = process.communicate(input=contents)
2671 return error or None
2672 except ValueError as e:
2673 return e
2674
2675
Saagar Sanghavifceeaae2020-08-12 16:40:362676def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472677 """Check that IDL and JSON files do not contain syntax errors."""
2678 actions = {
2679 '.idl': _GetIDLParseError,
2680 '.json': _GetJSONParseError,
2681 }
[email protected]99171a92014-06-03 08:44:472682 # Most JSON files are preprocessed and support comments, but these do not.
2683 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042684 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472685 ]
2686 # Only run IDL checker on files in these directories.
2687 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042688 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2689 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472690 ]
2691
2692 def get_action(affected_file):
2693 filename = affected_file.LocalPath()
2694 return actions.get(input_api.os_path.splitext(filename)[1])
2695
[email protected]99171a92014-06-03 08:44:472696 def FilterFile(affected_file):
2697 action = get_action(affected_file)
2698 if not action:
2699 return False
2700 path = affected_file.LocalPath()
2701
Erik Staab2dd72b12020-04-16 15:03:402702 if _MatchesFile(input_api,
2703 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2704 path):
[email protected]99171a92014-06-03 08:44:472705 return False
2706
2707 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162708 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472709 return False
2710 return True
2711
2712 results = []
2713 for affected_file in input_api.AffectedFiles(
2714 file_filter=FilterFile, include_deletes=False):
2715 action = get_action(affected_file)
2716 kwargs = {}
2717 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162718 _MatchesFile(input_api, json_no_comments_patterns,
2719 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472720 kwargs['eat_comments'] = False
2721 parse_error = action(input_api,
2722 affected_file.AbsoluteLocalPath(),
2723 **kwargs)
2724 if parse_error:
2725 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2726 (affected_file.LocalPath(), parse_error)))
2727 return results
2728
2729
Saagar Sanghavifceeaae2020-08-12 16:40:362730def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492731 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472732 import sys
[email protected]760deea2013-12-10 19:33:492733 original_sys_path = sys.path
2734 try:
2735 sys.path = sys.path + [input_api.os_path.join(
2736 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2737 import checkstyle
2738 finally:
2739 # Restore sys.path to what it was before.
2740 sys.path = original_sys_path
2741
2742 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092743 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442744 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492745
2746
Saagar Sanghavifceeaae2020-08-12 16:40:362747def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002748 """Checks to make sure devil is initialized correctly in python scripts."""
2749 script_common_initialize_pattern = input_api.re.compile(
2750 r'script_common\.InitializeEnvironment\(')
2751 devil_env_config_initialize = input_api.re.compile(
2752 r'devil_env\.config\.Initialize\(')
2753
2754 errors = []
2755
2756 sources = lambda affected_file: input_api.FilterSourceFile(
2757 affected_file,
James Cook24a504192020-07-23 00:08:442758 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2759 (r'^build[\\/]android[\\/]devil_chromium\.py',
2760 r'^third_party[\\/].*',)),
2761 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002762
2763 for f in input_api.AffectedSourceFiles(sources):
2764 for line_num, line in f.ChangedContents():
2765 if (script_common_initialize_pattern.search(line) or
2766 devil_env_config_initialize.search(line)):
2767 errors.append("%s:%d" % (f.LocalPath(), line_num))
2768
2769 results = []
2770
2771 if errors:
2772 results.append(output_api.PresubmitError(
2773 'Devil initialization should always be done using '
2774 'devil_chromium.Initialize() in the chromium project, to use better '
2775 'defaults for dependencies (ex. up-to-date version of adb).',
2776 errors))
2777
2778 return results
2779
2780
Sean Kau46e29bc2017-08-28 16:31:162781def _MatchesFile(input_api, patterns, path):
2782 for pattern in patterns:
2783 if input_api.re.search(pattern, path):
2784 return True
2785 return False
2786
2787
Daniel Cheng7052cdf2017-11-21 19:23:292788def _GetOwnersFilesToCheckForIpcOwners(input_api):
2789 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172790
Daniel Cheng7052cdf2017-11-21 19:23:292791 Returns:
2792 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2793 contain to cover IPC-related files with noparent reviewer rules.
2794 """
2795 # Whether or not a file affects IPC is (mostly) determined by a simple list
2796 # of filename patterns.
dchenge07de812016-06-20 19:27:172797 file_patterns = [
palmerb19a0932017-01-24 04:00:312798 # Legacy IPC:
dchenge07de812016-06-20 19:27:172799 '*_messages.cc',
2800 '*_messages*.h',
2801 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312802 # Mojo IPC:
dchenge07de812016-06-20 19:27:172803 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472804 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172805 '*_struct_traits*.*',
2806 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312807 '*.typemap',
2808 # Android native IPC:
2809 '*.aidl',
2810 # Blink uses a different file naming convention:
2811 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472812 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172813 '*StructTraits*.*',
2814 '*TypeConverter*.*',
2815 ]
2816
scottmg7a6ed5ba2016-11-04 18:22:042817 # These third_party directories do not contain IPCs, but contain files
2818 # matching the above patterns, which trigger false positives.
2819 exclude_paths = [
2820 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162821 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232822 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292823 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542824 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162825 # These files are just used to communicate between class loaders running
2826 # in the same process.
2827 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572828 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2829
scottmg7a6ed5ba2016-11-04 18:22:042830 ]
2831
dchenge07de812016-06-20 19:27:172832 # Dictionary mapping an OWNERS file path to Patterns.
2833 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2834 # rules ) to a PatternEntry.
2835 # PatternEntry is a dictionary with two keys:
2836 # - 'files': the files that are matched by this pattern
2837 # - 'rules': the per-file rules needed for this pattern
2838 # For example, if we expect OWNERS file to contain rules for *.mojom and
2839 # *_struct_traits*.*, Patterns might look like this:
2840 # {
2841 # '*.mojom': {
2842 # 'files': ...,
2843 # 'rules': [
2844 # 'per-file *.mojom=set noparent',
2845 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2846 # ],
2847 # },
2848 # '*_struct_traits*.*': {
2849 # 'files': ...,
2850 # 'rules': [
2851 # 'per-file *_struct_traits*.*=set noparent',
2852 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2853 # ],
2854 # },
2855 # }
2856 to_check = {}
2857
Daniel Cheng13ca61a882017-08-25 15:11:252858 def AddPatternToCheck(input_file, pattern):
2859 owners_file = input_api.os_path.join(
2860 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2861 if owners_file not in to_check:
2862 to_check[owners_file] = {}
2863 if pattern not in to_check[owners_file]:
2864 to_check[owners_file][pattern] = {
2865 'files': [],
2866 'rules': [
2867 'per-file %s=set noparent' % pattern,
2868 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2869 ]
2870 }
Vaclav Brozekd5de76a2018-03-17 07:57:502871 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252872
dchenge07de812016-06-20 19:27:172873 # Iterate through the affected files to see what we actually need to check
2874 # for. We should only nag patch authors about per-file rules if a file in that
2875 # directory would match that pattern. If a directory only contains *.mojom
2876 # files and no *_messages*.h files, we should only nag about rules for
2877 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252878 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262879 # Manifest files don't have a strong naming convention. Instead, try to find
2880 # affected .cc and .h files which look like they contain a manifest
2881 # definition.
2882 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2883 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2884 if (manifest_pattern.search(f.LocalPath()) and not
2885 test_manifest_pattern.search(f.LocalPath())):
2886 # We expect all actual service manifest files to contain at least one
2887 # qualified reference to service_manager::Manifest.
2888 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252889 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172890 for pattern in file_patterns:
2891 if input_api.fnmatch.fnmatch(
2892 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042893 skip = False
2894 for exclude in exclude_paths:
2895 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2896 skip = True
2897 break
2898 if skip:
2899 continue
Daniel Cheng13ca61a882017-08-25 15:11:252900 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172901 break
2902
Daniel Cheng7052cdf2017-11-21 19:23:292903 return to_check
2904
2905
Wez17c66962020-04-29 15:26:032906def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2907 """Adds OWNERS files to check for correct Fuchsia security owners."""
2908
2909 file_patterns = [
2910 # Component specifications.
2911 '*.cml', # Component Framework v2.
2912 '*.cmx', # Component Framework v1.
2913
2914 # Fuchsia IDL protocol specifications.
2915 '*.fidl',
2916 ]
2917
Joshua Peraza1ca6d392020-12-08 00:14:092918 # Don't check for owners files for changes in these directories.
2919 exclude_paths = [
2920 'third_party/crashpad/*',
2921 ]
2922
Wez17c66962020-04-29 15:26:032923 def AddPatternToCheck(input_file, pattern):
2924 owners_file = input_api.os_path.join(
2925 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2926 if owners_file not in to_check:
2927 to_check[owners_file] = {}
2928 if pattern not in to_check[owners_file]:
2929 to_check[owners_file][pattern] = {
2930 'files': [],
2931 'rules': [
2932 'per-file %s=set noparent' % pattern,
2933 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2934 ]
2935 }
2936 to_check[owners_file][pattern]['files'].append(input_file)
2937
2938 # Iterate through the affected files to see what we actually need to check
2939 # for. We should only nag patch authors about per-file rules if a file in that
2940 # directory would match that pattern.
2941 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092942 skip = False
2943 for exclude in exclude_paths:
2944 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2945 skip = True
2946 if skip:
2947 continue
2948
Wez17c66962020-04-29 15:26:032949 for pattern in file_patterns:
2950 if input_api.fnmatch.fnmatch(
2951 input_api.os_path.basename(f.LocalPath()), pattern):
2952 AddPatternToCheck(f, pattern)
2953 break
2954
2955 return to_check
2956
2957
Saagar Sanghavifceeaae2020-08-12 16:40:362958def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292959 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2960 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032961 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292962
2963 if to_check:
2964 # If there are any OWNERS files to check, there are IPC-related changes in
2965 # this CL. Auto-CC the review list.
2966 output_api.AppendCC('[email protected]')
2967
2968 # Go through the OWNERS files to check, filtering out rules that are already
2969 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172970 for owners_file, patterns in to_check.iteritems():
2971 try:
2972 with file(owners_file) as f:
2973 lines = set(f.read().splitlines())
2974 for entry in patterns.itervalues():
2975 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2976 ]
2977 except IOError:
2978 # No OWNERS file, so all the rules are definitely missing.
2979 continue
2980
2981 # All the remaining lines weren't found in OWNERS files, so emit an error.
2982 errors = []
2983 for owners_file, patterns in to_check.iteritems():
2984 missing_lines = []
2985 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502986 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172987 missing_lines.extend(entry['rules'])
2988 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2989 if missing_lines:
2990 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052991 'Because of the presence of files:\n%s\n\n'
2992 '%s needs the following %d lines added:\n\n%s' %
2993 ('\n'.join(files), owners_file, len(missing_lines),
2994 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172995
2996 results = []
2997 if errors:
vabrf5ce3bf92016-07-11 14:52:412998 if input_api.is_committing:
2999 output = output_api.PresubmitError
3000 else:
3001 output = output_api.PresubmitPromptWarning
3002 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593003 'Found OWNERS files that need to be updated for IPC security ' +
3004 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173005 long_text='\n\n'.join(errors)))
3006
3007 return results
3008
3009
Robert Sesek2c905332020-05-06 23:17:133010def _GetFilesUsingSecurityCriticalFunctions(input_api):
3011 """Checks affected files for changes to security-critical calls. This
3012 function checks the full change diff, to catch both additions/changes
3013 and removals.
3014
3015 Returns a dict keyed by file name, and the value is a set of detected
3016 functions.
3017 """
3018 # Map of function pretty name (displayed in an error) to the pattern to
3019 # match it with.
3020 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373021 'content::GetServiceSandboxType<>()':
3022 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133023 }
3024 _PATTERNS_TO_CHECK = {
3025 k: input_api.re.compile(v)
3026 for k, v in _PATTERNS_TO_CHECK.items()
3027 }
3028
3029 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3030 files_to_functions = {}
3031 for f in input_api.AffectedFiles():
3032 diff = f.GenerateScmDiff()
3033 for line in diff.split('\n'):
3034 # Not using just RightHandSideLines() because removing a
3035 # call to a security-critical function can be just as important
3036 # as adding or changing the arguments.
3037 if line.startswith('-') or (line.startswith('+') and
3038 not line.startswith('++')):
3039 for name, pattern in _PATTERNS_TO_CHECK.items():
3040 if pattern.search(line):
3041 path = f.LocalPath()
3042 if not path in files_to_functions:
3043 files_to_functions[path] = set()
3044 files_to_functions[path].add(name)
3045 return files_to_functions
3046
3047
Saagar Sanghavifceeaae2020-08-12 16:40:363048def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133049 """Checks that changes involving security-critical functions are reviewed
3050 by the security team.
3051 """
3052 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123053 if not len(files_to_functions):
3054 return []
Robert Sesek2c905332020-05-06 23:17:133055
Edward Lesmes1e9fade2021-02-08 20:31:123056 owner_email, reviewers = (
3057 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3058 input_api,
3059 None,
3060 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133061
Edward Lesmes1e9fade2021-02-08 20:31:123062 # Load the OWNERS file for security changes.
3063 owners_file = 'ipc/SECURITY_OWNERS'
3064 security_owners = input_api.owners_client.ListOwners(owners_file)
3065 has_security_owner = any([owner in reviewers for owner in security_owners])
3066 if has_security_owner:
3067 return []
Robert Sesek2c905332020-05-06 23:17:133068
Edward Lesmes1e9fade2021-02-08 20:31:123069 msg = 'The following files change calls to security-sensive functions\n' \
3070 'that need to be reviewed by {}.\n'.format(owners_file)
3071 for path, names in files_to_functions.items():
3072 msg += ' {}\n'.format(path)
3073 for name in names:
3074 msg += ' {}\n'.format(name)
3075 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133076
Edward Lesmes1e9fade2021-02-08 20:31:123077 if input_api.is_committing:
3078 output = output_api.PresubmitError
3079 else:
3080 output = output_api.PresubmitNotifyResult
3081 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133082
3083
Saagar Sanghavifceeaae2020-08-12 16:40:363084def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263085 """Checks that set noparent is only used together with an OWNERS file in
3086 //build/OWNERS.setnoparent (see also
3087 //docs/code_reviews.md#owners-files-details)
3088 """
3089 errors = []
3090
3091 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3092 allowed_owners_files = set()
3093 with open(allowed_owners_files_file, 'r') as f:
3094 for line in f:
3095 line = line.strip()
3096 if not line or line.startswith('#'):
3097 continue
3098 allowed_owners_files.add(line)
3099
3100 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3101
3102 for f in input_api.AffectedFiles(include_deletes=False):
3103 if not f.LocalPath().endswith('OWNERS'):
3104 continue
3105
3106 found_owners_files = set()
3107 found_set_noparent_lines = dict()
3108
3109 # Parse the OWNERS file.
3110 for lineno, line in enumerate(f.NewContents(), 1):
3111 line = line.strip()
3112 if line.startswith('set noparent'):
3113 found_set_noparent_lines[''] = lineno
3114 if line.startswith('file://'):
3115 if line in allowed_owners_files:
3116 found_owners_files.add('')
3117 if line.startswith('per-file'):
3118 match = per_file_pattern.match(line)
3119 if match:
3120 glob = match.group(1).strip()
3121 directive = match.group(2).strip()
3122 if directive == 'set noparent':
3123 found_set_noparent_lines[glob] = lineno
3124 if directive.startswith('file://'):
3125 if directive in allowed_owners_files:
3126 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153127
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263128 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403129 # listed in build/OWNERS.setnoparent. An exception is made for top level
3130 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143131 if (f.LocalPath().count('/') != 1 and
3132 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403133 for set_noparent_line in found_set_noparent_lines:
3134 if set_noparent_line in found_owners_files:
3135 continue
3136 errors.append(' %s:%d' % (f.LocalPath(),
3137 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263138
3139 results = []
3140 if errors:
3141 if input_api.is_committing:
3142 output = output_api.PresubmitError
3143 else:
3144 output = output_api.PresubmitPromptWarning
3145 results.append(output(
3146 'Found the following "set noparent" restrictions in OWNERS files that '
3147 'do not include owners from build/OWNERS.setnoparent:',
3148 long_text='\n\n'.join(errors)))
3149 return results
3150
3151
Saagar Sanghavifceeaae2020-08-12 16:40:363152def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313153 """Checks that added or removed lines in non third party affected
3154 header files do not lead to new useless class or struct forward
3155 declaration.
jbriance9e12f162016-11-25 07:57:503156 """
3157 results = []
3158 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3159 input_api.re.MULTILINE)
3160 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3161 input_api.re.MULTILINE)
3162 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313163 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193164 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493165 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313166 continue
3167
jbriance9e12f162016-11-25 07:57:503168 if not f.LocalPath().endswith('.h'):
3169 continue
3170
3171 contents = input_api.ReadFile(f)
3172 fwd_decls = input_api.re.findall(class_pattern, contents)
3173 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3174
3175 useless_fwd_decls = []
3176 for decl in fwd_decls:
3177 count = sum(1 for _ in input_api.re.finditer(
3178 r'\b%s\b' % input_api.re.escape(decl), contents))
3179 if count == 1:
3180 useless_fwd_decls.append(decl)
3181
3182 if not useless_fwd_decls:
3183 continue
3184
3185 for line in f.GenerateScmDiff().splitlines():
3186 if (line.startswith('-') and not line.startswith('--') or
3187 line.startswith('+') and not line.startswith('++')):
3188 for decl in useless_fwd_decls:
3189 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3190 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243191 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503192 (f.LocalPath(), decl)))
3193 useless_fwd_decls.remove(decl)
3194
3195 return results
3196
Jinsong Fan91ebbbd2019-04-16 14:57:173197def _CheckAndroidDebuggableBuild(input_api, output_api):
3198 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3199 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3200 this is a debuggable build of Android.
3201 """
3202 build_type_check_pattern = input_api.re.compile(
3203 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3204
3205 errors = []
3206
3207 sources = lambda affected_file: input_api.FilterSourceFile(
3208 affected_file,
James Cook24a504192020-07-23 00:08:443209 files_to_skip=(_EXCLUDED_PATHS +
3210 _TEST_CODE_EXCLUDED_PATHS +
3211 input_api.DEFAULT_FILES_TO_SKIP +
3212 (r"^android_webview[\\/]support_library[\\/]"
3213 "boundary_interfaces[\\/]",
3214 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3215 r'^third_party[\\/].*',
3216 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3217 r"webview[\\/]chromium[\\/]License.*",)),
3218 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173219
3220 for f in input_api.AffectedSourceFiles(sources):
3221 for line_num, line in f.ChangedContents():
3222 if build_type_check_pattern.search(line):
3223 errors.append("%s:%d" % (f.LocalPath(), line_num))
3224
3225 results = []
3226
3227 if errors:
3228 results.append(output_api.PresubmitPromptWarning(
3229 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3230 ' Please use BuildInfo.isDebugAndroid() instead.',
3231 errors))
3232
3233 return results
jbriance9e12f162016-11-25 07:57:503234
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493235# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293236def _CheckAndroidToastUsage(input_api, output_api):
3237 """Checks that code uses org.chromium.ui.widget.Toast instead of
3238 android.widget.Toast (Chromium Toast doesn't force hardware
3239 acceleration on low-end devices, saving memory).
3240 """
3241 toast_import_pattern = input_api.re.compile(
3242 r'^import android\.widget\.Toast;$')
3243
3244 errors = []
3245
3246 sources = lambda affected_file: input_api.FilterSourceFile(
3247 affected_file,
James Cook24a504192020-07-23 00:08:443248 files_to_skip=(_EXCLUDED_PATHS +
3249 _TEST_CODE_EXCLUDED_PATHS +
3250 input_api.DEFAULT_FILES_TO_SKIP +
3251 (r'^chromecast[\\/].*',
3252 r'^remoting[\\/].*')),
3253 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293254
3255 for f in input_api.AffectedSourceFiles(sources):
3256 for line_num, line in f.ChangedContents():
3257 if toast_import_pattern.search(line):
3258 errors.append("%s:%d" % (f.LocalPath(), line_num))
3259
3260 results = []
3261
3262 if errors:
3263 results.append(output_api.PresubmitError(
3264 'android.widget.Toast usage is detected. Android toasts use hardware'
3265 ' acceleration, and can be\ncostly on low-end devices. Please use'
3266 ' org.chromium.ui.widget.Toast instead.\n'
3267 'Contact [email protected] if you have any questions.',
3268 errors))
3269
3270 return results
3271
3272
dgnaa68d5e2015-06-10 10:08:223273def _CheckAndroidCrLogUsage(input_api, output_api):
3274 """Checks that new logs using org.chromium.base.Log:
3275 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513276 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223277 """
pkotwicza1dd0b002016-05-16 14:41:043278
torne89540622017-03-24 19:41:303279 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043280 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303281 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043282 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303283 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043284 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3285 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093286 # The customtabs_benchmark is a small app that does not depend on Chromium
3287 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043288 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043289 ]
3290
dgnaa68d5e2015-06-10 10:08:223291 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123292 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3293 class_in_base_pattern = input_api.re.compile(
3294 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3295 has_some_log_import_pattern = input_api.re.compile(
3296 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223297 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553298 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223299 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463300 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553301 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223302
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463303 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443304 sources = lambda x: input_api.FilterSourceFile(x,
3305 files_to_check=[r'.*\.java$'],
3306 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123307
dgnaa68d5e2015-06-10 10:08:223308 tag_decl_errors = []
3309 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123310 tag_errors = []
dgn38736db2015-09-18 19:20:513311 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123312 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223313
3314 for f in input_api.AffectedSourceFiles(sources):
3315 file_content = input_api.ReadFile(f)
3316 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223317 # Per line checks
dgn87d9fb62015-06-12 09:15:123318 if (cr_log_import_pattern.search(file_content) or
3319 (class_in_base_pattern.search(file_content) and
3320 not has_some_log_import_pattern.search(file_content))):
3321 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223322 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553323 if rough_log_decl_pattern.search(line):
3324 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223325
3326 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123327 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223328 if match:
3329 has_modified_logs = True
3330
3331 # Make sure it uses "TAG"
3332 if not match.group('tag') == 'TAG':
3333 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123334 else:
3335 # Report non cr Log function calls in changed lines
3336 for line_num, line in f.ChangedContents():
3337 if log_call_pattern.search(line):
3338 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223339
3340 # Per file checks
3341 if has_modified_logs:
3342 # Make sure the tag is using the "cr" prefix and is not too long
3343 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513344 tag_name = match.group('name') if match else None
3345 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223346 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513347 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223348 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513349 elif '.' in tag_name:
3350 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223351
3352 results = []
3353 if tag_decl_errors:
3354 results.append(output_api.PresubmitPromptWarning(
3355 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513356 '"private static final String TAG = "<package tag>".\n'
3357 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223358 tag_decl_errors))
3359
3360 if tag_length_errors:
3361 results.append(output_api.PresubmitError(
3362 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513363 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223364 tag_length_errors))
3365
3366 if tag_errors:
3367 results.append(output_api.PresubmitPromptWarning(
3368 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3369 tag_errors))
3370
dgn87d9fb62015-06-12 09:15:123371 if util_log_errors:
dgn4401aa52015-04-29 16:26:173372 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123373 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3374 util_log_errors))
3375
dgn38736db2015-09-18 19:20:513376 if tag_with_dot_errors:
3377 results.append(output_api.PresubmitPromptWarning(
3378 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3379 tag_with_dot_errors))
3380
dgn4401aa52015-04-29 16:26:173381 return results
3382
3383
Yoland Yanb92fa522017-08-28 17:37:063384def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3385 """Checks that junit.framework.* is no longer used."""
3386 deprecated_junit_framework_pattern = input_api.re.compile(
3387 r'^import junit\.framework\..*;',
3388 input_api.re.MULTILINE)
3389 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443390 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063391 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133392 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063393 for line_num, line in f.ChangedContents():
3394 if deprecated_junit_framework_pattern.search(line):
3395 errors.append("%s:%d" % (f.LocalPath(), line_num))
3396
3397 results = []
3398 if errors:
3399 results.append(output_api.PresubmitError(
3400 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3401 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3402 ' if you have any question.', errors))
3403 return results
3404
3405
3406def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3407 """Checks that if new Java test classes have inheritance.
3408 Either the new test class is JUnit3 test or it is a JUnit4 test class
3409 with a base class, either case is undesirable.
3410 """
3411 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3412
3413 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443414 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063415 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133416 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063417 if not f.OldContents():
3418 class_declaration_start_flag = False
3419 for line_num, line in f.ChangedContents():
3420 if class_declaration_pattern.search(line):
3421 class_declaration_start_flag = True
3422 if class_declaration_start_flag and ' extends ' in line:
3423 errors.append('%s:%d' % (f.LocalPath(), line_num))
3424 if '{' in line:
3425 class_declaration_start_flag = False
3426
3427 results = []
3428 if errors:
3429 results.append(output_api.PresubmitPromptWarning(
3430 'The newly created files include Test classes that inherits from base'
3431 ' class. Please do not use inheritance in JUnit4 tests or add new'
3432 ' JUnit3 tests. Contact [email protected] if you have any'
3433 ' questions.', errors))
3434 return results
3435
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203436
yolandyan45001472016-12-21 21:12:423437def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3438 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3439 deprecated_annotation_import_pattern = input_api.re.compile(
3440 r'^import android\.test\.suitebuilder\.annotation\..*;',
3441 input_api.re.MULTILINE)
3442 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443443 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423444 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133445 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423446 for line_num, line in f.ChangedContents():
3447 if deprecated_annotation_import_pattern.search(line):
3448 errors.append("%s:%d" % (f.LocalPath(), line_num))
3449
3450 results = []
3451 if errors:
3452 results.append(output_api.PresubmitError(
3453 'Annotations in android.test.suitebuilder.annotation have been'
3454 ' deprecated since API level 24. Please use android.support.test.filters'
3455 ' from //third_party/android_support_test_runner:runner_java instead.'
3456 ' Contact [email protected] if you have any questions.', errors))
3457 return results
3458
3459
agrieve7b6479d82015-10-07 14:24:223460def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3461 """Checks if MDPI assets are placed in a correct directory."""
3462 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3463 ('/res/drawable/' in f.LocalPath() or
3464 '/res/drawable-ldrtl/' in f.LocalPath()))
3465 errors = []
3466 for f in input_api.AffectedFiles(include_deletes=False,
3467 file_filter=file_filter):
3468 errors.append(' %s' % f.LocalPath())
3469
3470 results = []
3471 if errors:
3472 results.append(output_api.PresubmitError(
3473 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3474 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3475 '/res/drawable-ldrtl/.\n'
3476 'Contact [email protected] if you have questions.', errors))
3477 return results
3478
3479
Nate Fischer535972b2017-09-16 01:06:183480def _CheckAndroidWebkitImports(input_api, output_api):
3481 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353482 android.webview.ValueCallback except in the WebView glue layer
3483 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183484 """
3485 valuecallback_import_pattern = input_api.re.compile(
3486 r'^import android\.webkit\.ValueCallback;$')
3487
3488 errors = []
3489
3490 sources = lambda affected_file: input_api.FilterSourceFile(
3491 affected_file,
James Cook24a504192020-07-23 00:08:443492 files_to_skip=(_EXCLUDED_PATHS +
3493 _TEST_CODE_EXCLUDED_PATHS +
3494 input_api.DEFAULT_FILES_TO_SKIP +
3495 (r'^android_webview[\\/]glue[\\/].*',
3496 r'^weblayer[\\/].*',)),
3497 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183498
3499 for f in input_api.AffectedSourceFiles(sources):
3500 for line_num, line in f.ChangedContents():
3501 if valuecallback_import_pattern.search(line):
3502 errors.append("%s:%d" % (f.LocalPath(), line_num))
3503
3504 results = []
3505
3506 if errors:
3507 results.append(output_api.PresubmitError(
3508 'android.webkit.ValueCallback usage is detected outside of the glue'
3509 ' layer. To stay compatible with the support library, android.webkit.*'
3510 ' classes should only be used inside the glue layer and'
3511 ' org.chromium.base.Callback should be used instead.',
3512 errors))
3513
3514 return results
3515
3516
Becky Zhou7c69b50992018-12-10 19:37:573517def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3518 """Checks Android XML styles """
3519 import sys
3520 original_sys_path = sys.path
3521 try:
3522 sys.path = sys.path + [input_api.os_path.join(
3523 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3524 import checkxmlstyle
3525 finally:
3526 # Restore sys.path to what it was before.
3527 sys.path = original_sys_path
3528
3529 if is_check_on_upload:
3530 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3531 else:
3532 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3533
3534
agrievef32bcc72016-04-04 14:57:403535class PydepsChecker(object):
3536 def __init__(self, input_api, pydeps_files):
3537 self._file_cache = {}
3538 self._input_api = input_api
3539 self._pydeps_files = pydeps_files
3540
3541 def _LoadFile(self, path):
3542 """Returns the list of paths within a .pydeps file relative to //."""
3543 if path not in self._file_cache:
3544 with open(path) as f:
3545 self._file_cache[path] = f.read()
3546 return self._file_cache[path]
3547
3548 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3549 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393550 pydeps_data = self._LoadFile(pydeps_path)
3551 uses_gn_paths = '--gn-paths' in pydeps_data
3552 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3553 if uses_gn_paths:
3554 # Paths look like: //foo/bar/baz
3555 return (e[2:] for e in entries)
3556 else:
3557 # Paths look like: path/relative/to/file.pydeps
3558 os_path = self._input_api.os_path
3559 pydeps_dir = os_path.dirname(pydeps_path)
3560 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403561
3562 def _CreateFilesToPydepsMap(self):
3563 """Returns a map of local_path -> list_of_pydeps."""
3564 ret = {}
3565 for pydep_local_path in self._pydeps_files:
3566 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3567 ret.setdefault(path, []).append(pydep_local_path)
3568 return ret
3569
3570 def ComputeAffectedPydeps(self):
3571 """Returns an iterable of .pydeps files that might need regenerating."""
3572 affected_pydeps = set()
3573 file_to_pydeps_map = None
3574 for f in self._input_api.AffectedFiles(include_deletes=True):
3575 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463576 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3577 # subrepositories. We can't figure out which files change, so re-check
3578 # all files.
3579 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383580 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3581 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403582 return self._pydeps_files
3583 elif local_path.endswith('.pydeps'):
3584 if local_path in self._pydeps_files:
3585 affected_pydeps.add(local_path)
3586 elif local_path.endswith('.py'):
3587 if file_to_pydeps_map is None:
3588 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3589 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3590 return affected_pydeps
3591
3592 def DetermineIfStale(self, pydeps_path):
3593 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413594 import difflib
John Budorick47ca3fe2018-02-10 00:53:103595 import os
3596
agrievef32bcc72016-04-04 14:57:403597 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033598 if old_pydeps_data:
3599 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393600 if '--output' not in cmd:
3601 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033602 old_contents = old_pydeps_data[2:]
3603 else:
3604 # A default cmd that should work in most cases (as long as pydeps filename
3605 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3606 # file is empty/new.
3607 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3608 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3609 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103610 env = dict(os.environ)
3611 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403612 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103613 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413614 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033615 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413616 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403617
3618
Tibor Goldschwendt360793f72019-06-25 18:23:493619def _ParseGclientArgs():
3620 args = {}
3621 with open('build/config/gclient_args.gni', 'r') as f:
3622 for line in f:
3623 line = line.strip()
3624 if not line or line.startswith('#'):
3625 continue
3626 attribute, value = line.split('=')
3627 args[attribute.strip()] = value.strip()
3628 return args
3629
3630
Saagar Sanghavifceeaae2020-08-12 16:40:363631def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403632 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403633 # This check is for Python dependency lists (.pydeps files), and involves
3634 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3635 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283636 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003637 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493638 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403639 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403640 results = []
3641 # First, check for new / deleted .pydeps.
3642 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033643 # Check whether we are running the presubmit check for a file in src.
3644 # f.LocalPath is relative to repo (src, or internal repo).
3645 # os_path.exists is relative to src repo.
3646 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3647 # to src and we can conclude that the pydeps is in src.
3648 if input_api.os_path.exists(f.LocalPath()):
3649 if f.LocalPath().endswith('.pydeps'):
3650 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3651 results.append(output_api.PresubmitError(
3652 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3653 'remove %s' % f.LocalPath()))
3654 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3655 results.append(output_api.PresubmitError(
3656 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3657 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403658
3659 if results:
3660 return results
3661
Mohamed Heikal7cd4d8312020-06-16 16:49:403662 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3663 affected_pydeps = set(checker.ComputeAffectedPydeps())
3664 affected_android_pydeps = affected_pydeps.intersection(
3665 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3666 if affected_android_pydeps and not is_android:
3667 results.append(output_api.PresubmitPromptOrNotify(
3668 'You have changed python files that may affect pydeps for android\n'
3669 'specific scripts. However, the relevant presumbit check cannot be\n'
3670 'run because you are not using an Android checkout. To validate that\n'
3671 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3672 'use the android-internal-presubmit optional trybot.\n'
3673 'Possibly stale pydeps files:\n{}'.format(
3674 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403675
Mohamed Heikal7cd4d8312020-06-16 16:49:403676 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3677 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403678 try:
phajdan.jr0d9878552016-11-04 10:49:413679 result = checker.DetermineIfStale(pydep_path)
3680 if result:
3681 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403682 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413683 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3684 'To regenerate, run:\n\n %s' %
3685 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403686 except input_api.subprocess.CalledProcessError as error:
3687 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3688 long_text=error.output)]
3689
3690 return results
3691
3692
Saagar Sanghavifceeaae2020-08-12 16:40:363693def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433694 """Checks to make sure no header files have |Singleton<|."""
3695 def FileFilter(affected_file):
3696 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443697 files_to_skip = (_EXCLUDED_PATHS +
3698 input_api.DEFAULT_FILES_TO_SKIP +
3699 (r"^base[\\/]memory[\\/]singleton\.h$",
3700 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3701 r"quic_singleton_impl\.h$"))
3702 return input_api.FilterSourceFile(affected_file,
3703 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433704
sergeyu34d21222015-09-16 00:11:443705 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433706 files = []
3707 for f in input_api.AffectedSourceFiles(FileFilter):
3708 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3709 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3710 contents = input_api.ReadFile(f)
3711 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243712 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433713 pattern.search(line)):
3714 files.append(f)
3715 break
3716
3717 if files:
yolandyandaabc6d2016-04-18 18:29:393718 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443719 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433720 'Please move them to an appropriate source file so that the ' +
3721 'template gets instantiated in a single compilation unit.',
3722 files) ]
3723 return []
3724
3725
[email protected]fd20b902014-05-09 02:14:533726_DEPRECATED_CSS = [
3727 # Values
3728 ( "-webkit-box", "flex" ),
3729 ( "-webkit-inline-box", "inline-flex" ),
3730 ( "-webkit-flex", "flex" ),
3731 ( "-webkit-inline-flex", "inline-flex" ),
3732 ( "-webkit-min-content", "min-content" ),
3733 ( "-webkit-max-content", "max-content" ),
3734
3735 # Properties
3736 ( "-webkit-background-clip", "background-clip" ),
3737 ( "-webkit-background-origin", "background-origin" ),
3738 ( "-webkit-background-size", "background-size" ),
3739 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443740 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533741
3742 # Functions
3743 ( "-webkit-gradient", "gradient" ),
3744 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3745 ( "-webkit-linear-gradient", "linear-gradient" ),
3746 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3747 ( "-webkit-radial-gradient", "radial-gradient" ),
3748 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3749]
3750
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203751
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493752# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363753def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533754 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253755 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343756 documentation and iOS CSS for dom distiller
3757 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253758 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533759 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493760 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443761 files_to_skip = (_EXCLUDED_PATHS +
3762 _TEST_CODE_EXCLUDED_PATHS +
3763 input_api.DEFAULT_FILES_TO_SKIP +
3764 (r"^chrome/common/extensions/docs",
3765 r"^chrome/docs",
3766 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3767 r"^components/neterror/resources/neterror.css",
3768 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253769 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443770 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533771 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3772 for line_num, line in fpath.ChangedContents():
3773 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023774 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533775 results.append(output_api.PresubmitError(
3776 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3777 (fpath.LocalPath(), line_num, deprecated_value, value)))
3778 return results
3779
mohan.reddyf21db962014-10-16 12:26:473780
Saagar Sanghavifceeaae2020-08-12 16:40:363781def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363782 bad_files = {}
3783 for f in input_api.AffectedFiles(include_deletes=False):
3784 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493785 not f.LocalPath().startswith('third_party/blink') and
3786 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363787 continue
3788
Daniel Bratell65b033262019-04-23 08:17:063789 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363790 continue
3791
Vaclav Brozekd5de76a2018-03-17 07:57:503792 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363793 if "#include" in line and "../" in line]
3794 if not relative_includes:
3795 continue
3796 bad_files[f.LocalPath()] = relative_includes
3797
3798 if not bad_files:
3799 return []
3800
3801 error_descriptions = []
3802 for file_path, bad_lines in bad_files.iteritems():
3803 error_description = file_path
3804 for line in bad_lines:
3805 error_description += '\n ' + line
3806 error_descriptions.append(error_description)
3807
3808 results = []
3809 results.append(output_api.PresubmitError(
3810 'You added one or more relative #include paths (including "../").\n'
3811 'These shouldn\'t be used because they can be used to include headers\n'
3812 'from code that\'s not correctly specified as a dependency in the\n'
3813 'relevant BUILD.gn file(s).',
3814 error_descriptions))
3815
3816 return results
3817
Takeshi Yoshinoe387aa32017-08-02 13:16:133818
Saagar Sanghavifceeaae2020-08-12 16:40:363819def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063820 """Check that nobody tries to include a cc file. It's a relatively
3821 common error which results in duplicate symbols in object
3822 files. This may not always break the build until someone later gets
3823 very confusing linking errors."""
3824 results = []
3825 for f in input_api.AffectedFiles(include_deletes=False):
3826 # We let third_party code do whatever it wants
3827 if (f.LocalPath().startswith('third_party') and
3828 not f.LocalPath().startswith('third_party/blink') and
3829 not f.LocalPath().startswith('third_party\\blink')):
3830 continue
3831
3832 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3833 continue
3834
3835 for _, line in f.ChangedContents():
3836 if line.startswith('#include "'):
3837 included_file = line.split('"')[1]
3838 if _IsCPlusPlusFile(input_api, included_file):
3839 # The most common naming for external files with C++ code,
3840 # apart from standard headers, is to call them foo.inc, but
3841 # Chromium sometimes uses foo-inc.cc so allow that as well.
3842 if not included_file.endswith(('.h', '-inc.cc')):
3843 results.append(output_api.PresubmitError(
3844 'Only header files or .inc files should be included in other\n'
3845 'C++ files. Compiling the contents of a cc file more than once\n'
3846 'will cause duplicate information in the build which may later\n'
3847 'result in strange link_errors.\n' +
3848 f.LocalPath() + ':\n ' +
3849 line))
3850
3851 return results
3852
3853
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203854def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3855 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.Dict):
3858 return 'Value at line %d must be a dict' % value.lineno
3859 if len(value.keys) != 1:
3860 return 'Dict at line %d must have single entry' % value.lineno
3861 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3862 return (
3863 'Entry at line %d must have a string literal \'filepath\' as key' %
3864 value.lineno)
3865 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133866
Takeshi Yoshinoe387aa32017-08-02 13:16:133867
Sergey Ulanov4af16052018-11-08 02:41:463868def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203869 if not isinstance(key, ast.Str):
3870 return 'Key at line %d must be a string literal' % key.lineno
3871 if not isinstance(value, ast.List):
3872 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463873 for element in value.elts:
3874 if not isinstance(element, ast.Str):
3875 return 'Watchlist elements on line %d is not a string' % key.lineno
3876 if not email_regex.match(element.s):
3877 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3878 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203879 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133880
Takeshi Yoshinoe387aa32017-08-02 13:16:133881
Sergey Ulanov4af16052018-11-08 02:41:463882def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203883 mismatch_template = (
3884 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3885 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133886
Sergey Ulanov4af16052018-11-08 02:41:463887 email_regex = input_api.re.compile(
3888 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3889
3890 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203891 i = 0
3892 last_key = ''
3893 while True:
3894 if i >= len(wd_dict.keys):
3895 if i >= len(w_dict.keys):
3896 return None
3897 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3898 elif i >= len(w_dict.keys):
3899 return (
3900 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133901
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203902 wd_key = wd_dict.keys[i]
3903 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203905 result = _CheckWatchlistDefinitionsEntrySyntax(
3906 wd_key, wd_dict.values[i], ast)
3907 if result is not None:
3908 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133909
Sergey Ulanov4af16052018-11-08 02:41:463910 result = _CheckWatchlistsEntrySyntax(
3911 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203912 if result is not None:
3913 return 'Bad entry in WATCHLISTS dict: %s' % result
3914
3915 if wd_key.s != w_key.s:
3916 return mismatch_template % (
3917 '%s at line %d' % (wd_key.s, wd_key.lineno),
3918 '%s at line %d' % (w_key.s, w_key.lineno))
3919
3920 if wd_key.s < last_key:
3921 return (
3922 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3923 (wd_key.lineno, w_key.lineno))
3924 last_key = wd_key.s
3925
3926 i = i + 1
3927
3928
Sergey Ulanov4af16052018-11-08 02:41:463929def _CheckWATCHLISTSSyntax(expression, input_api):
3930 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203931 if not isinstance(expression, ast.Expression):
3932 return 'WATCHLISTS file must contain a valid expression'
3933 dictionary = expression.body
3934 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3935 return 'WATCHLISTS file must have single dict with exactly two entries'
3936
3937 first_key = dictionary.keys[0]
3938 first_value = dictionary.values[0]
3939 second_key = dictionary.keys[1]
3940 second_value = dictionary.values[1]
3941
3942 if (not isinstance(first_key, ast.Str) or
3943 first_key.s != 'WATCHLIST_DEFINITIONS' or
3944 not isinstance(first_value, ast.Dict)):
3945 return (
3946 'The first entry of the dict in WATCHLISTS file must be '
3947 'WATCHLIST_DEFINITIONS dict')
3948
3949 if (not isinstance(second_key, ast.Str) or
3950 second_key.s != 'WATCHLISTS' or
3951 not isinstance(second_value, ast.Dict)):
3952 return (
3953 'The second entry of the dict in WATCHLISTS file must be '
3954 'WATCHLISTS dict')
3955
Sergey Ulanov4af16052018-11-08 02:41:463956 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133957
3958
Saagar Sanghavifceeaae2020-08-12 16:40:363959def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133960 for f in input_api.AffectedFiles(include_deletes=False):
3961 if f.LocalPath() == 'WATCHLISTS':
3962 contents = input_api.ReadFile(f, 'r')
3963
3964 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203965 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133966 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203967 # Get an AST tree for it and scan the tree for detailed style checking.
3968 expression = input_api.ast.parse(
3969 contents, filename='WATCHLISTS', mode='eval')
3970 except ValueError as e:
3971 return [output_api.PresubmitError(
3972 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3973 except SyntaxError as e:
3974 return [output_api.PresubmitError(
3975 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3976 except TypeError as e:
3977 return [output_api.PresubmitError(
3978 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133979
Sergey Ulanov4af16052018-11-08 02:41:463980 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203981 if result is not None:
3982 return [output_api.PresubmitError(result)]
3983 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
3985 return []
3986
3987
Andrew Grieve1b290e4a22020-11-24 20:07:013988def CheckGnGlobForward(input_api, output_api):
3989 """Checks that forward_variables_from(invoker, "*") follows best practices.
3990
3991 As documented at //build/docs/writing_gn_templates.md
3992 """
3993 def gn_files(f):
3994 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3995
3996 problems = []
3997 for f in input_api.AffectedSourceFiles(gn_files):
3998 for line_num, line in f.ChangedContents():
3999 if 'forward_variables_from(invoker, "*")' in line:
4000 problems.append(
4001 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
4002 f.LocalPath(), line_num))
4003
4004 if problems:
4005 return [output_api.PresubmitPromptWarning(
4006 'forward_variables_from("*") without exclusions',
4007 items=sorted(problems),
4008 long_text=('The variables "visibilty" and "test_only" should be '
4009 'explicitly listed in forward_variables_from(). For more '
4010 'details, see:\n'
4011 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4012 'build/docs/writing_gn_templates.md'
4013 '#Using-forward_variables_from'))]
4014 return []
4015
4016
Saagar Sanghavifceeaae2020-08-12 16:40:364017def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194018 """Checks that newly added header files have corresponding GN changes.
4019 Note that this is only a heuristic. To be precise, run script:
4020 build/check_gn_headers.py.
4021 """
4022
4023 def headers(f):
4024 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444025 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194026
4027 new_headers = []
4028 for f in input_api.AffectedSourceFiles(headers):
4029 if f.Action() != 'A':
4030 continue
4031 new_headers.append(f.LocalPath())
4032
4033 def gn_files(f):
James Cook24a504192020-07-23 00:08:444034 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194035
4036 all_gn_changed_contents = ''
4037 for f in input_api.AffectedSourceFiles(gn_files):
4038 for _, line in f.ChangedContents():
4039 all_gn_changed_contents += line
4040
4041 problems = []
4042 for header in new_headers:
4043 basename = input_api.os_path.basename(header)
4044 if basename not in all_gn_changed_contents:
4045 problems.append(header)
4046
4047 if problems:
4048 return [output_api.PresubmitPromptWarning(
4049 'Missing GN changes for new header files', items=sorted(problems),
4050 long_text='Please double check whether newly added header files need '
4051 'corresponding changes in gn or gni files.\nThis checking is only a '
4052 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4053 'Read https://crbug.com/661774 for more info.')]
4054 return []
4055
4056
Saagar Sanghavifceeaae2020-08-12 16:40:364057def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024058 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4059
4060 This assumes we won't intentionally reference one product from the other
4061 product.
4062 """
4063 all_problems = []
4064 test_cases = [{
4065 "filename_postfix": "google_chrome_strings.grd",
4066 "correct_name": "Chrome",
4067 "incorrect_name": "Chromium",
4068 }, {
4069 "filename_postfix": "chromium_strings.grd",
4070 "correct_name": "Chromium",
4071 "incorrect_name": "Chrome",
4072 }]
4073
4074 for test_case in test_cases:
4075 problems = []
4076 filename_filter = lambda x: x.LocalPath().endswith(
4077 test_case["filename_postfix"])
4078
4079 # Check each new line. Can yield false positives in multiline comments, but
4080 # easier than trying to parse the XML because messages can have nested
4081 # children, and associating message elements with affected lines is hard.
4082 for f in input_api.AffectedSourceFiles(filename_filter):
4083 for line_num, line in f.ChangedContents():
4084 if "<message" in line or "<!--" in line or "-->" in line:
4085 continue
4086 if test_case["incorrect_name"] in line:
4087 problems.append(
4088 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4089
4090 if problems:
4091 message = (
4092 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4093 % (test_case["correct_name"], test_case["correct_name"],
4094 test_case["incorrect_name"]))
4095 all_problems.append(
4096 output_api.PresubmitPromptWarning(message, items=problems))
4097
4098 return all_problems
4099
4100
Saagar Sanghavifceeaae2020-08-12 16:40:364101def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364102 """Avoid large files, especially binary files, in the repository since
4103 git doesn't scale well for those. They will be in everyone's repo
4104 clones forever, forever making Chromium slower to clone and work
4105 with."""
4106
4107 # Uploading files to cloud storage is not trivial so we don't want
4108 # to set the limit too low, but the upper limit for "normal" large
4109 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4110 # anything over 20 MB is exceptional.
4111 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4112
4113 too_large_files = []
4114 for f in input_api.AffectedFiles():
4115 # Check both added and modified files (but not deleted files).
4116 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384117 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364118 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4119 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4120
4121 if too_large_files:
4122 message = (
4123 'Do not commit large files to git since git scales badly for those.\n' +
4124 'Instead put the large files in cloud storage and use DEPS to\n' +
4125 'fetch them.\n' + '\n'.join(too_large_files)
4126 )
4127 return [output_api.PresubmitError(
4128 'Too large files found in commit', long_text=message + '\n')]
4129 else:
4130 return []
4131
Max Morozb47503b2019-08-08 21:03:274132
Saagar Sanghavifceeaae2020-08-12 16:40:364133def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274134 """Checks specific for fuzz target sources."""
4135 EXPORTED_SYMBOLS = [
4136 'LLVMFuzzerInitialize',
4137 'LLVMFuzzerCustomMutator',
4138 'LLVMFuzzerCustomCrossOver',
4139 'LLVMFuzzerMutate',
4140 ]
4141
4142 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4143
4144 def FilterFile(affected_file):
4145 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444146 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4147 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274148
4149 return input_api.FilterSourceFile(
4150 affected_file,
James Cook24a504192020-07-23 00:08:444151 files_to_check=[files_to_check],
4152 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274153
4154 files_with_missing_header = []
4155 for f in input_api.AffectedSourceFiles(FilterFile):
4156 contents = input_api.ReadFile(f, 'r')
4157 if REQUIRED_HEADER in contents:
4158 continue
4159
4160 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4161 files_with_missing_header.append(f.LocalPath())
4162
4163 if not files_with_missing_header:
4164 return []
4165
4166 long_text = (
4167 'If you define any of the libFuzzer optional functions (%s), it is '
4168 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4169 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4170 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4171 'to access command line arguments passed to the fuzzer. Instead, prefer '
4172 'static initialization and shared resources as documented in '
4173 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4174 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4175 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4176 )
4177
4178 return [output_api.PresubmitPromptWarning(
4179 message="Missing '%s' in:" % REQUIRED_HEADER,
4180 items=files_with_missing_header,
4181 long_text=long_text)]
4182
4183
Mohamed Heikald048240a2019-11-12 16:57:374184def _CheckNewImagesWarning(input_api, output_api):
4185 """
4186 Warns authors who add images into the repo to make sure their images are
4187 optimized before committing.
4188 """
4189 images_added = False
4190 image_paths = []
4191 errors = []
4192 filter_lambda = lambda x: input_api.FilterSourceFile(
4193 x,
James Cook24a504192020-07-23 00:08:444194 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4195 + input_api.DEFAULT_FILES_TO_SKIP),
4196 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374197 )
4198 for f in input_api.AffectedFiles(
4199 include_deletes=False, file_filter=filter_lambda):
4200 local_path = f.LocalPath().lower()
4201 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4202 images_added = True
4203 image_paths.append(f)
4204 if images_added:
4205 errors.append(output_api.PresubmitPromptWarning(
4206 'It looks like you are trying to commit some images. If these are '
4207 'non-test-only images, please make sure to read and apply the tips in '
4208 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4209 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4210 'FYI only and will not block your CL on the CQ.', image_paths))
4211 return errors
4212
4213
Saagar Sanghavifceeaae2020-08-12 16:40:364214def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574215 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224216 results = []
dgnaa68d5e2015-06-10 10:08:224217 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174218 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224219 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294220 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064221 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4222 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424223 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184224 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574225 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374226 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154227 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574228 return results
4229
Saagar Sanghavifceeaae2020-08-12 16:40:364230def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574231 """Groups commit checks that target android code."""
4232 results = []
4233 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224234 return results
4235
Chris Hall59f8d0c72020-05-01 07:31:194236# TODO(chrishall): could we additionally match on any path owned by
4237# ui/accessibility/OWNERS ?
4238_ACCESSIBILITY_PATHS = (
4239 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4240 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4241 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4242 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4243 r"^content[\\/]browser[\\/]accessibility[\\/]",
4244 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4245 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4246 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4247 r"^ui[\\/]accessibility[\\/]",
4248 r"^ui[\\/]views[\\/]accessibility[\\/]",
4249)
4250
Saagar Sanghavifceeaae2020-08-12 16:40:364251def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194252 """Checks that commits to accessibility code contain an AX-Relnotes field in
4253 their commit message."""
4254 def FileFilter(affected_file):
4255 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444256 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194257
4258 # Only consider changes affecting accessibility paths.
4259 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4260 return []
4261
Akihiro Ota08108e542020-05-20 15:30:534262 # AX-Relnotes can appear in either the description or the footer.
4263 # When searching the description, require 'AX-Relnotes:' to appear at the
4264 # beginning of a line.
4265 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4266 description_has_relnotes = any(ax_regex.match(line)
4267 for line in input_api.change.DescriptionText().lower().splitlines())
4268
4269 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4270 'AX-Relnotes', [])
4271 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194272 return []
4273
4274 # TODO(chrishall): link to Relnotes documentation in message.
4275 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4276 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4277 "user-facing changes"
4278 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4279 "user-facing effects"
4280 "\n if this is confusing or annoying then please contact members "
4281 "of ui/accessibility/OWNERS.")
4282
4283 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224284
seanmccullough4a9356252021-04-08 19:54:094285# string pattern, sequence of strings to show when pattern matches,
4286# error flag. True if match is a presubmit error, otherwise it's a warning.
4287_NON_INCLUSIVE_TERMS = (
4288 (
4289 # Note that \b pattern in python re is pretty particular. In this
4290 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4291 # ...' will not. This may require some tweaking to catch these cases
4292 # without triggering a lot of false positives. Leaving it naive and
4293 # less matchy for now.
4294 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4295 (
4296 'Please don\'t use blacklist, whitelist, ' # nocheck
4297 'or slave in your', # nocheck
4298 'code and make every effort to use other terms. Using "// nocheck"',
4299 '"# nocheck" or "<!-- nocheck -->"',
4300 'at the end of the offending line will bypass this PRESUBMIT error',
4301 'but avoid using this whenever possible. Reach out to',
4302 '[email protected] if you have questions'),
4303 True),)
4304
Saagar Sanghavifceeaae2020-08-12 16:40:364305def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394306 """Checks common to both upload and commit."""
4307 results = []
4308 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384309 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544310 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084311
4312 author = input_api.change.author_email
4313 if author and author not in _KNOWN_ROBOTS:
4314 results.extend(
4315 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4316
[email protected]9f919cc2013-07-31 03:04:044317 results.extend(
4318 input_api.canned_checks.CheckChangeHasNoTabs(
4319 input_api,
4320 output_api,
4321 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434322 results.extend(input_api.RunTests(
4323 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244324
Edward Lesmesce51df52020-08-04 22:10:174325 dirmd_bin = input_api.os_path.join(
4326 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4327 results.extend(input_api.RunTests(
4328 input_api.canned_checks.CheckDirMetadataFormat(
4329 input_api, output_api, dirmd_bin)))
4330 results.extend(
4331 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4332 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554333 results.extend(
4334 input_api.canned_checks.CheckNoNewMetadataInOwners(
4335 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094336 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4337 input_api, output_api,
4338 excluded_directories_relative_path = [
4339 'infra',
4340 'inclusive_language_presubmit_exempt_dirs.txt'
4341 ],
4342 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174343
Vaclav Brozekcdc7defb2018-03-20 09:54:354344 for f in input_api.AffectedFiles():
4345 path, name = input_api.os_path.split(f.LocalPath())
4346 if name == 'PRESUBMIT.py':
4347 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004348 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4349 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074350 # The PRESUBMIT.py file (and the directory containing it) might
4351 # have been affected by being moved or removed, so only try to
4352 # run the tests if they still exist.
4353 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4354 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444355 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394356 return results
[email protected]1f7b4172010-01-28 01:17:344357
[email protected]b337cb5b2011-01-23 21:24:054358
Saagar Sanghavifceeaae2020-08-12 16:40:364359def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494360 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4361 if f.LocalPath().endswith(('.orig', '.rej'))]
4362 if problems:
4363 return [output_api.PresubmitError(
4364 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034365 else:
4366 return []
[email protected]b8079ae4a2012-12-05 19:56:494367
4368
Saagar Sanghavifceeaae2020-08-12 16:40:364369def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214370 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4371 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4372 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074373 include_re = input_api.re.compile(
4374 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4375 extension_re = input_api.re.compile(r'\.[a-z]+$')
4376 errors = []
4377 for f in input_api.AffectedFiles():
4378 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4379 continue
4380 found_line_number = None
4381 found_macro = None
4382 for line_num, line in f.ChangedContents():
4383 match = macro_re.search(line)
4384 if match:
4385 found_line_number = line_num
4386 found_macro = match.group(2)
4387 break
4388 if not found_line_number:
4389 continue
4390
4391 found_include = False
4392 for line in f.NewContents():
4393 if include_re.search(line):
4394 found_include = True
4395 break
4396 if found_include:
4397 continue
4398
4399 if not f.LocalPath().endswith('.h'):
4400 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4401 try:
4402 content = input_api.ReadFile(primary_header_path, 'r')
4403 if include_re.search(content):
4404 continue
4405 except IOError:
4406 pass
4407 errors.append('%s:%d %s macro is used without including build/'
4408 'build_config.h.'
4409 % (f.LocalPath(), found_line_number, found_macro))
4410 if errors:
4411 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4412 return []
4413
4414
[email protected]b00342e7f2013-03-26 16:21:544415def _DidYouMeanOSMacro(bad_macro):
4416 try:
4417 return {'A': 'OS_ANDROID',
4418 'B': 'OS_BSD',
4419 'C': 'OS_CHROMEOS',
4420 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444421 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544422 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444423 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544424 'N': 'OS_NACL',
4425 'O': 'OS_OPENBSD',
4426 'P': 'OS_POSIX',
4427 'S': 'OS_SOLARIS',
4428 'W': 'OS_WIN'}[bad_macro[3].upper()]
4429 except KeyError:
4430 return ''
4431
4432
4433def _CheckForInvalidOSMacrosInFile(input_api, f):
4434 """Check for sensible looking, totally invalid OS macros."""
4435 preprocessor_statement = input_api.re.compile(r'^\s*#')
4436 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4437 results = []
4438 for lnum, line in f.ChangedContents():
4439 if preprocessor_statement.search(line):
4440 for match in os_macro.finditer(line):
4441 if not match.group(1) in _VALID_OS_MACROS:
4442 good = _DidYouMeanOSMacro(match.group(1))
4443 did_you_mean = ' (did you mean %s?)' % good if good else ''
4444 results.append(' %s:%d %s%s' % (f.LocalPath(),
4445 lnum,
4446 match.group(1),
4447 did_you_mean))
4448 return results
4449
4450
Saagar Sanghavifceeaae2020-08-12 16:40:364451def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544452 """Check all affected files for invalid OS macros."""
4453 bad_macros = []
tzik3f295992018-12-04 20:32:234454 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474455 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544456 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4457
4458 if not bad_macros:
4459 return []
4460
4461 return [output_api.PresubmitError(
4462 'Possibly invalid OS macro[s] found. Please fix your code\n'
4463 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4464
lliabraa35bab3932014-10-01 12:16:444465
4466def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4467 """Check all affected files for invalid "if defined" macros."""
4468 ALWAYS_DEFINED_MACROS = (
4469 "TARGET_CPU_PPC",
4470 "TARGET_CPU_PPC64",
4471 "TARGET_CPU_68K",
4472 "TARGET_CPU_X86",
4473 "TARGET_CPU_ARM",
4474 "TARGET_CPU_MIPS",
4475 "TARGET_CPU_SPARC",
4476 "TARGET_CPU_ALPHA",
4477 "TARGET_IPHONE_SIMULATOR",
4478 "TARGET_OS_EMBEDDED",
4479 "TARGET_OS_IPHONE",
4480 "TARGET_OS_MAC",
4481 "TARGET_OS_UNIX",
4482 "TARGET_OS_WIN32",
4483 )
4484 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4485 results = []
4486 for lnum, line in f.ChangedContents():
4487 for match in ifdef_macro.finditer(line):
4488 if match.group(1) in ALWAYS_DEFINED_MACROS:
4489 always_defined = ' %s is always defined. ' % match.group(1)
4490 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4491 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4492 lnum,
4493 always_defined,
4494 did_you_mean))
4495 return results
4496
4497
Saagar Sanghavifceeaae2020-08-12 16:40:364498def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444499 """Check all affected files for invalid "if defined" macros."""
4500 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054501 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444502 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054503 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214504 continue
lliabraa35bab3932014-10-01 12:16:444505 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4506 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4507
4508 if not bad_macros:
4509 return []
4510
4511 return [output_api.PresubmitError(
4512 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4513 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4514 bad_macros)]
4515
4516
Saagar Sanghavifceeaae2020-08-12 16:40:364517def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044518 """Check for same IPC rules described in
4519 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4520 """
4521 base_pattern = r'IPC_ENUM_TRAITS\('
4522 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4523 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4524
4525 problems = []
4526 for f in input_api.AffectedSourceFiles(None):
4527 local_path = f.LocalPath()
4528 if not local_path.endswith('.h'):
4529 continue
4530 for line_number, line in f.ChangedContents():
4531 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4532 problems.append(
4533 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4534
4535 if problems:
4536 return [output_api.PresubmitPromptWarning(
4537 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4538 else:
4539 return []
4540
[email protected]b00342e7f2013-03-26 16:21:544541
Saagar Sanghavifceeaae2020-08-12 16:40:364542def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054543 """Check to make sure no files being submitted have long paths.
4544 This causes issues on Windows.
4545 """
4546 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194547 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054548 local_path = f.LocalPath()
4549 # Windows has a path limit of 260 characters. Limit path length to 200 so
4550 # that we have some extra for the prefix on dev machines and the bots.
4551 if len(local_path) > 200:
4552 problems.append(local_path)
4553
4554 if problems:
4555 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4556 else:
4557 return []
4558
4559
Saagar Sanghavifceeaae2020-08-12 16:40:364560def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144561 """Check that header files have proper guards against multiple inclusion.
4562 If a file should not have such guards (and it probably should) then it
4563 should include the string "no-include-guard-because-multiply-included".
4564 """
Daniel Bratell6a75baef62018-06-04 10:04:454565 def is_chromium_header_file(f):
4566 # We only check header files under the control of the Chromium
4567 # project. That is, those outside third_party apart from
4568 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324569 # We also exclude *_message_generator.h headers as they use
4570 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454571 file_with_path = input_api.os_path.normpath(f.LocalPath())
4572 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324573 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454574 (not file_with_path.startswith('third_party') or
4575 file_with_path.startswith(
4576 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144577
4578 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344579 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144580
4581 errors = []
4582
Daniel Bratell6a75baef62018-06-04 10:04:454583 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144584 guard_name = None
4585 guard_line_number = None
4586 seen_guard_end = False
4587
4588 file_with_path = input_api.os_path.normpath(f.LocalPath())
4589 base_file_name = input_api.os_path.splitext(
4590 input_api.os_path.basename(file_with_path))[0]
4591 upper_base_file_name = base_file_name.upper()
4592
4593 expected_guard = replace_special_with_underscore(
4594 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144595
4596 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574597 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4598 # are too many (1000+) files with slight deviations from the
4599 # coding style. The most important part is that the include guard
4600 # is there, and that it's unique, not the name so this check is
4601 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144602 #
4603 # As code becomes more uniform, this could be made stricter.
4604
4605 guard_name_pattern_list = [
4606 # Anything with the right suffix (maybe with an extra _).
4607 r'\w+_H__?',
4608
Daniel Bratell39b5b062018-05-16 18:09:574609 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144610 r'\w+_h',
4611
4612 # Anything including the uppercase name of the file.
4613 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4614 upper_base_file_name)) + r'\w*',
4615 ]
4616 guard_name_pattern = '|'.join(guard_name_pattern_list)
4617 guard_pattern = input_api.re.compile(
4618 r'#ifndef\s+(' + guard_name_pattern + ')')
4619
4620 for line_number, line in enumerate(f.NewContents()):
4621 if 'no-include-guard-because-multiply-included' in line:
4622 guard_name = 'DUMMY' # To not trigger check outside the loop.
4623 break
4624
4625 if guard_name is None:
4626 match = guard_pattern.match(line)
4627 if match:
4628 guard_name = match.group(1)
4629 guard_line_number = line_number
4630
Daniel Bratell39b5b062018-05-16 18:09:574631 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454632 # don't match the chromium style guide, but new files should
4633 # get it right.
4634 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574635 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144636 errors.append(output_api.PresubmitPromptWarning(
4637 'Header using the wrong include guard name %s' % guard_name,
4638 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574639 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144640 else:
4641 # The line after #ifndef should have a #define of the same name.
4642 if line_number == guard_line_number + 1:
4643 expected_line = '#define %s' % guard_name
4644 if line != expected_line:
4645 errors.append(output_api.PresubmitPromptWarning(
4646 'Missing "%s" for include guard' % expected_line,
4647 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4648 'Expected: %r\nGot: %r' % (expected_line, line)))
4649
4650 if not seen_guard_end and line == '#endif // %s' % guard_name:
4651 seen_guard_end = True
4652 elif seen_guard_end:
4653 if line.strip() != '':
4654 errors.append(output_api.PresubmitPromptWarning(
4655 'Include guard %s not covering the whole file' % (
4656 guard_name), [f.LocalPath()]))
4657 break # Nothing else to check and enough to warn once.
4658
4659 if guard_name is None:
4660 errors.append(output_api.PresubmitPromptWarning(
4661 'Missing include guard %s' % expected_guard,
4662 [f.LocalPath()],
4663 'Missing include guard in %s\n'
4664 'Recommended name: %s\n'
4665 'This check can be disabled by having the string\n'
4666 'no-include-guard-because-multiply-included in the header.' %
4667 (f.LocalPath(), expected_guard)))
4668
4669 return errors
4670
4671
Saagar Sanghavifceeaae2020-08-12 16:40:364672def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234673 """Check source code and known ascii text files for Windows style line
4674 endings.
4675 """
earthdok1b5e0ee2015-03-10 15:19:104676 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234677
4678 file_inclusion_pattern = (
4679 known_text_files,
4680 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4681 )
4682
mostynbb639aca52015-01-07 20:31:234683 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534684 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444685 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534686 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504687 include_file = False
4688 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234689 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504690 include_file = True
4691 if include_file:
4692 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234693
4694 if problems:
4695 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4696 'these files to contain Windows style line endings?\n' +
4697 '\n'.join(problems))]
4698
4699 return []
4700
Jose Magana2b456f22021-03-09 23:26:404701def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4702 """Check source code for use of Chrome App technologies being
4703 deprecated.
4704 """
4705
4706 def _CheckForDeprecatedTech(input_api, output_api,
4707 detection_list, files_to_check = None, files_to_skip = None):
4708
4709 if (files_to_check or files_to_skip):
4710 source_file_filter = lambda f: input_api.FilterSourceFile(
4711 f, files_to_check=files_to_check,
4712 files_to_skip=files_to_skip)
4713 else:
4714 source_file_filter = None
4715
4716 problems = []
4717
4718 for f in input_api.AffectedSourceFiles(source_file_filter):
4719 if f.Action() == 'D':
4720 continue
4721 for _, line in f.ChangedContents():
4722 if any( detect in line for detect in detection_list ):
4723 problems.append(f.LocalPath())
4724
4725 return problems
4726
4727 # to avoid this presubmit script triggering warnings
4728 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4729
4730 problems =[]
4731
4732 # NMF: any files with extensions .nmf or NMF
4733 _NMF_FILES = r'\.(nmf|NMF)$'
4734 problems += _CheckForDeprecatedTech(input_api, output_api,
4735 detection_list = [''], # any change to the file will trigger warning
4736 files_to_check = [ r'.+%s' % _NMF_FILES ])
4737
4738 # MANIFEST: any manifest.json that in its diff includes "app":
4739 _MANIFEST_FILES = r'(manifest\.json)$'
4740 problems += _CheckForDeprecatedTech(input_api, output_api,
4741 detection_list = ['"app":'],
4742 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4743
4744 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4745 problems += _CheckForDeprecatedTech(input_api, output_api,
4746 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4747 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4748
4749 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4750 problems += _CheckForDeprecatedTech(input_api, output_api,
4751 detection_list = ['#include "ppapi','#include <ppapi'],
4752 files_to_check = (
4753 r'.+%s' % _HEADER_EXTENSIONS,
4754 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4755 files_to_skip = [r"^ppapi[\\/]"] )
4756
4757 # Chrome Apps: any JS/TS file that references an API in the list below.
4758 # This should include the list of Chrome Apps APIs that are not Chrome
4759 # Extensions APIs as documented in:
4760 # https://developer.chrome.com/docs/apps/migration/
4761 detection_list_chrome_apps = [
4762 'chrome.accessibilityFeatures',
4763 'chrome.alarms',
4764 'chrome.app.runtime',
4765 'chrome.app.window',
4766 'chrome.audio',
4767 'chrome.bluetooth',
4768 'chrome.bluetoothLowEnergy',
4769 'chrome.bluetoothSocket',
4770 'chrome.browser',
4771 'chrome.commands',
4772 'chrome.contextMenus',
4773 'chrome.documentScan',
4774 'chrome.events',
4775 'chrome.extensionTypes',
4776 'chrome.fileSystem',
4777 'chrome.fileSystemProvider',
4778 'chrome.gcm',
4779 'chrome.hid',
4780 'chrome.i18n',
4781 'chrome.identity',
4782 'chrome.idle',
4783 'chrome.instanceID',
4784 'chrome.mdns',
4785 'chrome.mediaGalleries',
4786 'chrome.networking.onc',
4787 'chrome.notifications',
4788 'chrome.permissions',
4789 'chrome.power',
4790 'chrome.printerProvider',
4791 'chrome.runtime',
4792 'chrome.serial',
4793 'chrome.sockets.tcp',
4794 'chrome.sockets.tcpServer',
4795 'chrome.sockets.udp',
4796 'chrome.storage',
4797 'chrome.syncFileSystem',
4798 'chrome.system.cpu',
4799 'chrome.system.display',
4800 'chrome.system.memory',
4801 'chrome.system.network',
4802 'chrome.system.storage',
4803 'chrome.tts',
4804 'chrome.types',
4805 'chrome.usb',
4806 'chrome.virtualKeyboard',
4807 'chrome.vpnProvider',
4808 'chrome.wallpaper'
4809 ]
4810 _JS_FILES = r'\.(js|ts)$'
4811 problems += _CheckForDeprecatedTech(input_api, output_api,
4812 detection_list = detection_list_chrome_apps,
4813 files_to_check = [ r'.+%s' % _JS_FILES ],
4814 files_to_skip = files_to_skip)
4815
4816 if problems:
4817 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4818 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4819 ' PNaCl, PPAPI). See this blog post for more details:\n'
4820 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4821 'and this documentation for options to replace these technologies:\n'
4822 'https://developer.chrome.com/docs/apps/migration/\n'+
4823 '\n'.join(problems))]
4824
4825 return []
4826
mostynbb639aca52015-01-07 20:31:234827
Saagar Sanghavifceeaae2020-08-12 16:40:364828def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134829 """Checks that all source files use SYSLOG properly."""
4830 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364831 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564832 for line_number, line in f.ChangedContents():
4833 if 'SYSLOG' in line:
4834 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4835
pastarmovj89f7ee12016-09-20 14:58:134836 if syslog_files:
4837 return [output_api.PresubmitPromptWarning(
4838 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4839 ' calls.\nFiles to check:\n', items=syslog_files)]
4840 return []
4841
4842
[email protected]1f7b4172010-01-28 01:17:344843def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364844 if input_api.version < [2, 0, 0]:
4845 return [output_api.PresubmitError("Your depot_tools is out of date. "
4846 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4847 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344848 results = []
scottmg39b29952014-12-08 18:31:284849 results.extend(
jam93a6ee792017-02-08 23:59:224850 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544851 return results
[email protected]ca8d1982009-02-19 16:33:124852
4853
[email protected]1bfb8322014-04-23 01:02:414854def GetTryServerMasterForBot(bot):
4855 """Returns the Try Server master for the given bot.
4856
[email protected]0bb112362014-07-26 04:38:324857 It tries to guess the master from the bot name, but may still fail
4858 and return None. There is no longer a default master.
4859 """
4860 # Potentially ambiguous bot names are listed explicitly.
4861 master_map = {
tandriie5587792016-07-14 00:34:504862 'chromium_presubmit': 'master.tryserver.chromium.linux',
4863 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414864 }
[email protected]0bb112362014-07-26 04:38:324865 master = master_map.get(bot)
4866 if not master:
wnwen4fbaab82016-05-25 12:54:364867 if 'android' in bot:
tandriie5587792016-07-14 00:34:504868 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364869 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504870 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324871 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504872 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324873 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504874 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324875 return master
[email protected]1bfb8322014-04-23 01:02:414876
4877
[email protected]ca8d1982009-02-19 16:33:124878def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364879 if input_api.version < [2, 0, 0]:
4880 return [output_api.PresubmitError("Your depot_tools is out of date. "
4881 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4882 "but your version is %d.%d.%d" % tuple(input_api.version))]
4883
[email protected]fe5f57c52009-06-05 14:25:544884 results = []
[email protected]fe5f57c52009-06-05 14:25:544885 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274886 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344887 input_api,
4888 output_api,
[email protected]2fdd1f362013-01-16 03:56:034889 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274890
jam93a6ee792017-02-08 23:59:224891 results.extend(
4892 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544893 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4894 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384895 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4896 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414897 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4898 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544899 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144900
4901
Saagar Sanghavifceeaae2020-08-12 16:40:364902def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264903 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024904 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4905 # footer is set to true.
4906 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264907 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024908 footer.lower()
4909 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264910 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024911
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144912 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264913 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144914 import sys
4915 from io import StringIO
4916
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144917 new_or_added_paths = set(f.LocalPath()
4918 for f in input_api.AffectedFiles()
4919 if (f.Action() == 'A' or f.Action() == 'M'))
4920 removed_paths = set(f.LocalPath()
4921 for f in input_api.AffectedFiles(include_deletes=True)
4922 if f.Action() == 'D')
4923
Andrew Grieve0e8790c2020-09-03 17:27:324924 affected_grds = [
4925 f for f in input_api.AffectedFiles()
4926 if f.LocalPath().endswith(('.grd', '.grdp'))
4927 ]
4928 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164929 if not affected_grds:
4930 return []
4931
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144932 affected_png_paths = [f.AbsoluteLocalPath()
4933 for f in input_api.AffectedFiles()
4934 if (f.LocalPath().endswith('.png'))]
4935
4936 # Check for screenshots. Developers can upload screenshots using
4937 # tools/translation/upload_screenshots.py which finds and uploads
4938 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4939 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4940 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4941 #
4942 # The logic here is as follows:
4943 #
4944 # - If the CL has a .png file under the screenshots directory for a grd
4945 # file, warn the developer. Actual images should never be checked into the
4946 # Chrome repo.
4947 #
4948 # - If the CL contains modified or new messages in grd files and doesn't
4949 # contain the corresponding .sha1 files, warn the developer to add images
4950 # and upload them via tools/translation/upload_screenshots.py.
4951 #
4952 # - If the CL contains modified or new messages in grd files and the
4953 # corresponding .sha1 files, everything looks good.
4954 #
4955 # - If the CL contains removed messages in grd files but the corresponding
4956 # .sha1 files aren't removed, warn the developer to remove them.
4957 unnecessary_screenshots = []
4958 missing_sha1 = []
4959 unnecessary_sha1_files = []
4960
Rainhard Findlingfc31844c52020-05-15 09:58:264961 # This checks verifies that the ICU syntax of messages this CL touched is
4962 # valid, and reports any found syntax errors.
4963 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4964 # without developers being aware of them. Later on, such ICU syntax errors
4965 # break message extraction for translation, hence would block Chromium
4966 # translations until they are fixed.
4967 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144968
4969 def _CheckScreenshotAdded(screenshots_dir, message_id):
4970 sha1_path = input_api.os_path.join(
4971 screenshots_dir, message_id + '.png.sha1')
4972 if sha1_path not in new_or_added_paths:
4973 missing_sha1.append(sha1_path)
4974
4975
4976 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4977 sha1_path = input_api.os_path.join(
4978 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034979 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144980 unnecessary_sha1_files.append(sha1_path)
4981
Rainhard Findlingfc31844c52020-05-15 09:58:264982
4983 def _ValidateIcuSyntax(text, level, signatures):
4984 """Validates ICU syntax of a text string.
4985
4986 Check if text looks similar to ICU and checks for ICU syntax correctness
4987 in this case. Reports various issues with ICU syntax and values of
4988 variants. Supports checking of nested messages. Accumulate information of
4989 each ICU messages found in the text for further checking.
4990
4991 Args:
4992 text: a string to check.
4993 level: a number of current nesting level.
4994 signatures: an accumulator, a list of tuple of (level, variable,
4995 kind, variants).
4996
4997 Returns:
4998 None if a string is not ICU or no issue detected.
4999 A tuple of (message, start index, end index) if an issue detected.
5000 """
5001 valid_types = {
5002 'plural': (frozenset(
5003 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5004 frozenset(['=1', 'other'])),
5005 'selectordinal': (frozenset(
5006 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5007 frozenset(['one', 'other'])),
5008 'select': (frozenset(), frozenset(['other'])),
5009 }
5010
5011 # Check if the message looks like an attempt to use ICU
5012 # plural. If yes - check if its syntax strictly matches ICU format.
5013 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5014 if not like:
5015 signatures.append((level, None, None, None))
5016 return
5017
5018 # Check for valid prefix and suffix
5019 m = re.match(
5020 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5021 r'(plural|selectordinal|select),\s*'
5022 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5023 if not m:
5024 return (('This message looks like an ICU plural, '
5025 'but does not follow ICU syntax.'), like.start(), like.end())
5026 starting, variable, kind, variant_pairs = m.groups()
5027 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5028 if depth:
5029 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5030 len(text))
5031 first = text[0]
5032 ending = text[last_pos:]
5033 if not starting:
5034 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5035 last_pos)
5036 if not ending or '}' not in ending:
5037 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5038 last_pos)
5039 elif first != '{':
5040 return (
5041 ('Invalid ICU format. Extra characters at the start of a complex '
5042 'message (go/icu-message-migration): "%s"') %
5043 starting, 0, len(starting))
5044 elif ending != '}':
5045 return (('Invalid ICU format. Extra characters at the end of a complex '
5046 'message (go/icu-message-migration): "%s"')
5047 % ending, last_pos - 1, len(text) - 1)
5048 if kind not in valid_types:
5049 return (('Unknown ICU message type %s. '
5050 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5051 known, required = valid_types[kind]
5052 defined_variants = set()
5053 for variant, variant_range, value, value_range in variants:
5054 start, end = variant_range
5055 if variant in defined_variants:
5056 return ('Variant "%s" is defined more than once' % variant,
5057 start, end)
5058 elif known and variant not in known:
5059 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5060 start, end)
5061 defined_variants.add(variant)
5062 # Check for nested structure
5063 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5064 if res:
5065 return (res[0], res[1] + value_range[0] + 1,
5066 res[2] + value_range[0] + 1)
5067 missing = required - defined_variants
5068 if missing:
5069 return ('Required variants missing: %s' % ', '.join(missing), 0,
5070 len(text))
5071 signatures.append((level, variable, kind, defined_variants))
5072
5073
5074 def _ParseIcuVariants(text, offset=0):
5075 """Parse variants part of ICU complex message.
5076
5077 Builds a tuple of variant names and values, as well as
5078 their offsets in the input string.
5079
5080 Args:
5081 text: a string to parse
5082 offset: additional offset to add to positions in the text to get correct
5083 position in the complete ICU string.
5084
5085 Returns:
5086 List of tuples, each tuple consist of four fields: variant name,
5087 variant name span (tuple of two integers), variant value, value
5088 span (tuple of two integers).
5089 """
5090 depth, start, end = 0, -1, -1
5091 variants = []
5092 key = None
5093 for idx, char in enumerate(text):
5094 if char == '{':
5095 if not depth:
5096 start = idx
5097 chunk = text[end + 1:start]
5098 key = chunk.strip()
5099 pos = offset + end + 1 + chunk.find(key)
5100 span = (pos, pos + len(key))
5101 depth += 1
5102 elif char == '}':
5103 if not depth:
5104 return variants, depth, offset + idx
5105 depth -= 1
5106 if not depth:
5107 end = idx
5108 variants.append((key, span, text[start:end + 1], (offset + start,
5109 offset + end + 1)))
5110 return variants, depth, offset + end + 1
5111
meacer8c0d3832019-12-26 21:46:165112 try:
5113 old_sys_path = sys.path
5114 sys.path = sys.path + [input_api.os_path.join(
5115 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5116 from helper import grd_helper
5117 finally:
5118 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
5120 for f in affected_grds:
5121 file_path = f.LocalPath()
5122 old_id_to_msg_map = {}
5123 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385124 # Note that this code doesn't check if the file has been deleted. This is
5125 # OK because it only uses the old and new file contents and doesn't load
5126 # the file via its path.
5127 # It's also possible that a file's content refers to a renamed or deleted
5128 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5129 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5130 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145131 if file_path.endswith('.grdp'):
5132 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585133 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395134 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145135 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585136 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395137 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138 else:
meacerff8a9b62019-12-10 19:43:585139 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585141 old_id_to_msg_map = grd_helper.GetGrdMessages(
5142 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145143 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585144 new_id_to_msg_map = grd_helper.GetGrdMessages(
5145 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145146
Rainhard Findlingd8d04372020-08-13 13:30:095147 grd_name, ext = input_api.os_path.splitext(
5148 input_api.os_path.basename(file_path))
5149 screenshots_dir = input_api.os_path.join(
5150 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5151
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145152 # Compute added, removed and modified message IDs.
5153 old_ids = set(old_id_to_msg_map)
5154 new_ids = set(new_id_to_msg_map)
5155 added_ids = new_ids - old_ids
5156 removed_ids = old_ids - new_ids
5157 modified_ids = set([])
5158 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355159 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095160 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5161 # The message content itself changed. Require an updated screenshot.
5162 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355163 elif old_id_to_msg_map[key].attrs['meaning'] != \
5164 new_id_to_msg_map[key].attrs['meaning']:
5165 # The message meaning changed. Ensure there is a screenshot for it.
5166 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5167 if sha1_path not in new_or_added_paths and not \
5168 input_api.os_path.exists(sha1_path):
5169 # There is neither a previous screenshot nor is a new one added now.
5170 # Require a screenshot.
5171 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145172
Rainhard Findlingfc31844c52020-05-15 09:58:265173 if run_screenshot_check:
5174 # Check the screenshot directory for .png files. Warn if there is any.
5175 for png_path in affected_png_paths:
5176 if png_path.startswith(screenshots_dir):
5177 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145178
Rainhard Findlingfc31844c52020-05-15 09:58:265179 for added_id in added_ids:
5180 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145181
Rainhard Findlingfc31844c52020-05-15 09:58:265182 for modified_id in modified_ids:
5183 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145184
Rainhard Findlingfc31844c52020-05-15 09:58:265185 for removed_id in removed_ids:
5186 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5187
5188 # Check new and changed strings for ICU syntax errors.
5189 for key in added_ids.union(modified_ids):
5190 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5191 err = _ValidateIcuSyntax(msg, 0, [])
5192 if err is not None:
5193 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145194
5195 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265196 if run_screenshot_check:
5197 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005198 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265199 'Do not include actual screenshots in the changelist. Run '
5200 'tools/translate/upload_screenshots.py to upload them instead:',
5201 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145202
Rainhard Findlingfc31844c52020-05-15 09:58:265203 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005204 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265205 'You are adding or modifying UI strings.\n'
5206 'To ensure the best translations, take screenshots of the relevant UI '
5207 '(https://g.co/chrome/translation) and add these files to your '
5208 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145209
Rainhard Findlingfc31844c52020-05-15 09:58:265210 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005211 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265212 'You removed strings associated with these files. Remove:',
5213 sorted(unnecessary_sha1_files)))
5214 else:
5215 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5216 'screenshots check.'))
5217
5218 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075219 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265220 'ICU syntax errors were found in the following strings (problems or '
5221 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145222
5223 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125224
5225
Saagar Sanghavifceeaae2020-08-12 16:40:365226def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125227 repo_root=None,
5228 translation_expectations_path=None,
5229 grd_files=None):
5230 import sys
5231 affected_grds = [f for f in input_api.AffectedFiles()
5232 if (f.LocalPath().endswith('.grd') or
5233 f.LocalPath().endswith('.grdp'))]
5234 if not affected_grds:
5235 return []
5236
5237 try:
5238 old_sys_path = sys.path
5239 sys.path = sys.path + [
5240 input_api.os_path.join(
5241 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5242 from helper import git_helper
5243 from helper import translation_helper
5244 finally:
5245 sys.path = old_sys_path
5246
5247 # Check that translation expectations can be parsed and we can get a list of
5248 # translatable grd files. |repo_root| and |translation_expectations_path| are
5249 # only passed by tests.
5250 if not repo_root:
5251 repo_root = input_api.PresubmitLocalPath()
5252 if not translation_expectations_path:
5253 translation_expectations_path = input_api.os_path.join(
5254 repo_root, 'tools', 'gritsettings',
5255 'translation_expectations.pyl')
5256 if not grd_files:
5257 grd_files = git_helper.list_grds_in_repository(repo_root)
5258
dpapad8e21b472020-10-23 17:15:035259 # Ignore bogus grd files used only for testing
5260 # ui/webui/resoucres/tools/generate_grd.py.
5261 ignore_path = input_api.os_path.join(
5262 'ui', 'webui', 'resources', 'tools', 'tests')
5263 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5264
Mustafa Emre Acer51f2f742020-03-09 19:41:125265 try:
5266 translation_helper.get_translatable_grds(repo_root, grd_files,
5267 translation_expectations_path)
5268 except Exception as e:
5269 return [output_api.PresubmitNotifyResult(
5270 'Failed to get a list of translatable grd files. This happens when:\n'
5271 ' - One of the modified grd or grdp files cannot be parsed or\n'
5272 ' - %s is not updated.\n'
5273 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5274 return []
Ken Rockotc31f4832020-05-29 18:58:515275
5276
Saagar Sanghavifceeaae2020-08-12 16:40:365277def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515278 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095279 changed_mojoms = input_api.AffectedFiles(
5280 include_deletes=True,
5281 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515282 delta = []
5283 for mojom in changed_mojoms:
5284 old_contents = ''.join(mojom.OldContents()) or None
5285 new_contents = ''.join(mojom.NewContents()) or None
5286 delta.append({
5287 'filename': mojom.LocalPath(),
5288 'old': '\n'.join(mojom.OldContents()) or None,
5289 'new': '\n'.join(mojom.NewContents()) or None,
5290 })
5291
5292 process = input_api.subprocess.Popen(
5293 [input_api.python_executable,
5294 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5295 'public', 'tools', 'mojom',
5296 'check_stable_mojom_compatibility.py'),
5297 '--src-root', input_api.PresubmitLocalPath()],
5298 stdin=input_api.subprocess.PIPE,
5299 stdout=input_api.subprocess.PIPE,
5300 stderr=input_api.subprocess.PIPE,
5301 universal_newlines=True)
5302 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5303 if process.returncode:
5304 return [output_api.PresubmitError(
5305 'One or more [Stable] mojom definitions appears to have been changed '
5306 'in a way that is not backward-compatible.',
5307 long_text=error)]
5308 return []
Dominic Battre645d42342020-12-04 16:14:105309
5310def CheckDeprecationOfPreferences(input_api, output_api):
5311 """Removing a preference should come with a deprecation."""
5312
5313 def FilterFile(affected_file):
5314 """Accept only .cc files and the like."""
5315 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5316 files_to_skip = (_EXCLUDED_PATHS +
5317 _TEST_CODE_EXCLUDED_PATHS +
5318 input_api.DEFAULT_FILES_TO_SKIP)
5319 return input_api.FilterSourceFile(
5320 affected_file,
5321 files_to_check=file_inclusion_pattern,
5322 files_to_skip=files_to_skip)
5323
5324 def ModifiedLines(affected_file):
5325 """Returns a list of tuples (line number, line text) of added and removed
5326 lines.
5327
5328 Deleted lines share the same line number as the previous line.
5329
5330 This relies on the scm diff output describing each changed code section
5331 with a line of the form
5332
5333 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5334 """
5335 line_num = 0
5336 modified_lines = []
5337 for line in affected_file.GenerateScmDiff().splitlines():
5338 # Extract <new line num> of the patch fragment (see format above).
5339 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5340 if m:
5341 line_num = int(m.groups(1)[0])
5342 continue
5343 if ((line.startswith('+') and not line.startswith('++')) or
5344 (line.startswith('-') and not line.startswith('--'))):
5345 modified_lines.append((line_num, line))
5346
5347 if not line.startswith('-'):
5348 line_num += 1
5349 return modified_lines
5350
5351 def FindLineWith(lines, needle):
5352 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5353
5354 If 0 or >1 lines contain `needle`, -1 is returned.
5355 """
5356 matching_line_numbers = [
5357 # + 1 for 1-based counting of line numbers.
5358 i + 1 for i, line
5359 in enumerate(lines)
5360 if needle in line]
5361 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5362
5363 def ModifiedPrefMigration(affected_file):
5364 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5365 # Determine first and last lines of MigrateObsolete.*Pref functions.
5366 new_contents = affected_file.NewContents();
5367 range_1 = (
5368 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5369 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5370 range_2 = (
5371 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5372 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5373 if (-1 in range_1 + range_2):
5374 raise Exception(
5375 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5376
5377 # Check whether any of the modified lines are part of the
5378 # MigrateObsolete.*Pref functions.
5379 for line_nr, line in ModifiedLines(affected_file):
5380 if (range_1[0] <= line_nr <= range_1[1] or
5381 range_2[0] <= line_nr <= range_2[1]):
5382 return True
5383 return False
5384
5385 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5386 browser_prefs_file_pattern = input_api.re.compile(
5387 r'chrome/browser/prefs/browser_prefs.cc')
5388
5389 changes = input_api.AffectedFiles(include_deletes=True,
5390 file_filter=FilterFile)
5391 potential_problems = []
5392 for f in changes:
5393 for line in f.GenerateScmDiff().splitlines():
5394 # Check deleted lines for pref registrations.
5395 if (line.startswith('-') and not line.startswith('--') and
5396 register_pref_pattern.search(line)):
5397 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5398
5399 if browser_prefs_file_pattern.search(f.LocalPath()):
5400 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5401 # assume that they knew that they have to deprecate preferences and don't
5402 # warn.
5403 try:
5404 if ModifiedPrefMigration(f):
5405 return []
5406 except Exception as e:
5407 return [output_api.PresubmitError(str(e))]
5408
5409 if potential_problems:
5410 return [output_api.PresubmitPromptWarning(
5411 'Discovered possible removal of preference registrations.\n\n'
5412 'Please make sure to properly deprecate preferences by clearing their\n'
5413 'value for a couple of milestones before finally removing the code.\n'
5414 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195415 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5416 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105417 'This may be a false positive warning (e.g. if you move preference\n'
5418 'registrations to a different place).\n',
5419 potential_problems
5420 )]
5421 return []