blob: 6e4453d4e1815d46623d08495059c83886a77f87 [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 (
1055 'Improper use of base::win::RoInitialize() has been implicated in a ',
1056 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
1057 'instead. See http://crbug.com/1197722 for more information.'
1058 ),
1059 True,
1060 (),
1061 ),
[email protected]127f18ec2012-06-16 05:05:591062)
1063
Mario Sanchez Prada2472cab2019-09-18 10:58:311064# Format: Sequence of tuples containing:
1065# * String pattern or, if starting with a slash, a regular expression.
1066# * Sequence of strings to show when the pattern matches.
1067_DEPRECATED_MOJO_TYPES = (
1068 (
1069 r'/\bmojo::AssociatedBinding\b',
1070 (
1071 'mojo::AssociatedBinding<Interface> is deprecated.',
1072 'Use mojo::AssociatedReceiver<Interface> instead.',
1073 ),
1074 ),
1075 (
1076 r'/\bmojo::AssociatedBindingSet\b',
1077 (
1078 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1079 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1080 ),
1081 ),
1082 (
1083 r'/\bmojo::AssociatedInterfacePtr\b',
1084 (
1085 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1086 'Use mojo::AssociatedRemote<Interface> instead.',
1087 ),
1088 ),
1089 (
1090 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1091 (
1092 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1093 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1094 ),
1095 ),
1096 (
1097 r'/\bmojo::AssociatedInterfaceRequest\b',
1098 (
1099 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1100 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1101 ),
1102 ),
1103 (
1104 r'/\bmojo::Binding\b',
1105 (
1106 'mojo::Binding<Interface> is deprecated.',
1107 'Use mojo::Receiver<Interface> instead.',
1108 ),
1109 ),
1110 (
1111 r'/\bmojo::BindingSet\b',
1112 (
1113 'mojo::BindingSet<Interface> is deprecated.',
1114 'Use mojo::ReceiverSet<Interface> instead.',
1115 ),
1116 ),
1117 (
1118 r'/\bmojo::InterfacePtr\b',
1119 (
1120 'mojo::InterfacePtr<Interface> is deprecated.',
1121 'Use mojo::Remote<Interface> instead.',
1122 ),
1123 ),
1124 (
1125 r'/\bmojo::InterfacePtrInfo\b',
1126 (
1127 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1128 'Use mojo::PendingRemote<Interface> instead.',
1129 ),
1130 ),
1131 (
1132 r'/\bmojo::InterfaceRequest\b',
1133 (
1134 'mojo::InterfaceRequest<Interface> is deprecated.',
1135 'Use mojo::PendingReceiver<Interface> instead.',
1136 ),
1137 ),
1138 (
1139 r'/\bmojo::MakeRequest\b',
1140 (
1141 'mojo::MakeRequest is deprecated.',
1142 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1143 ),
1144 ),
1145 (
1146 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1147 (
1148 'mojo::MakeRequest is deprecated.',
1149 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181150 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311151 ),
1152 ),
1153 (
1154 r'/\bmojo::MakeStrongBinding\b',
1155 (
1156 'mojo::MakeStrongBinding is deprecated.',
1157 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1158 'mojo::MakeSelfOwnedReceiver() instead.',
1159 ),
1160 ),
1161 (
1162 r'/\bmojo::MakeStrongAssociatedBinding\b',
1163 (
1164 'mojo::MakeStrongAssociatedBinding is deprecated.',
1165 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1166 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1167 ),
1168 ),
1169 (
Gyuyoung Kim4952ba62020-07-07 07:33:441170 r'/\bmojo::StrongAssociatedBinding\b',
1171 (
1172 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1173 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1174 ),
1175 ),
1176 (
1177 r'/\bmojo::StrongBinding\b',
1178 (
1179 'mojo::StrongBinding<Interface> is deprecated.',
1180 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1181 ),
1182 ),
1183 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311184 r'/\bmojo::StrongAssociatedBindingSet\b',
1185 (
1186 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1187 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1188 ),
1189 ),
1190 (
1191 r'/\bmojo::StrongBindingSet\b',
1192 (
1193 'mojo::StrongBindingSet<Interface> is deprecated.',
1194 'Use mojo::UniqueReceiverSet<Interface> instead.',
1195 ),
1196 ),
1197)
wnwenbdc444e2016-05-25 13:44:151198
mlamouria82272622014-09-16 18:45:041199_IPC_ENUM_TRAITS_DEPRECATED = (
1200 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501201 'See http://www.chromium.org/Home/chromium-security/education/'
1202 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041203
Stephen Martinis97a394142018-06-07 23:06:051204_LONG_PATH_ERROR = (
1205 'Some files included in this CL have file names that are too long (> 200'
1206 ' characters). If committed, these files will cause issues on Windows. See'
1207 ' https://crbug.com/612667 for more details.'
1208)
1209
Shenghua Zhangbfaa38b82017-11-16 21:58:021210_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041211 r".*[\\/]BuildHooksAndroidImpl\.java",
1212 r".*[\\/]LicenseContentProvider\.java",
1213 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281214 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021215]
[email protected]127f18ec2012-06-16 05:05:591216
Mohamed Heikald048240a2019-11-12 16:57:371217# List of image extensions that are used as resources in chromium.
1218_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1219
Sean Kau46e29bc2017-08-28 16:31:161220# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401221_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041222 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401223 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041224 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1225 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041226 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431227 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161228]
1229
1230
[email protected]b00342e7f2013-03-26 16:21:541231_VALID_OS_MACROS = (
1232 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081233 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541234 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441235 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121236 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541237 'OS_BSD',
1238 'OS_CAT', # For testing.
1239 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041240 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541241 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371242 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541243 'OS_IOS',
1244 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441245 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541246 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211247 'OS_NACL_NONSFI',
1248 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121249 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541250 'OS_OPENBSD',
1251 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371252 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541253 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541254 'OS_WIN',
1255)
1256
1257
Andrew Grieveb773bad2020-06-05 18:00:381258# These are not checked on the public chromium-presubmit trybot.
1259# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041260# checkouts.
agrievef32bcc72016-04-04 14:57:401261_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381262 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381263]
1264
1265
1266_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041267 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361268 'base/android/jni_generator/jni_generator.pydeps',
1269 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361270 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041271 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361272 'build/android/gyp/aar.pydeps',
1273 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271274 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361275 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381276 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361277 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021278 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221279 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111280 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361281 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361282 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361283 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111284 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041285 'build/android/gyp/create_app_bundle_apks.pydeps',
1286 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361287 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121288 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091289 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221290 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001291 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361292 'build/android/gyp/desugar.pydeps',
1293 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421294 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041295 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361296 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361297 'build/android/gyp/filter_zip.pydeps',
1298 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361299 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361300 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581301 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361302 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141303 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261304 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011305 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041306 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361307 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361308 'build/android/gyp/merge_manifest.pydeps',
1309 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221310 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361311 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461312 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241313 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461315 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561316 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/incremental_install/generate_android_manifest.pydeps',
1318 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041319 'build/android/resource_sizes.pydeps',
1320 'build/android/test_runner.pydeps',
1321 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361322 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361323 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321324 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271325 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1326 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041327 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001328 'components/cronet/tools/generate_javadoc.pydeps',
1329 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381330 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001331 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381332 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041333 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181334 'testing/scripts/run_isolated_script_test.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041335 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421336 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1337 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131338 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061339 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221340 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401341]
1342
wnwenbdc444e2016-05-25 13:44:151343
agrievef32bcc72016-04-04 14:57:401344_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1345
1346
Eric Boren6fd2b932018-01-25 15:05:081347# Bypass the AUTHORS check for these accounts.
1348_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591349 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451350 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591351 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521352 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071353 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041354 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271355 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041356 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161357 for s in ('chromium-internal-autoroll',)
1358 ) | set('%[email protected]' % s
1359 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081360
1361
Daniel Bratell65b033262019-04-23 08:17:061362def _IsCPlusPlusFile(input_api, file_path):
1363 """Returns True if this file contains C++-like code (and not Python,
1364 Go, Java, MarkDown, ...)"""
1365
1366 ext = input_api.os_path.splitext(file_path)[1]
1367 # This list is compatible with CppChecker.IsCppFile but we should
1368 # consider adding ".c" to it. If we do that we can use this function
1369 # at more places in the code.
1370 return ext in (
1371 '.h',
1372 '.cc',
1373 '.cpp',
1374 '.m',
1375 '.mm',
1376 )
1377
1378def _IsCPlusPlusHeaderFile(input_api, file_path):
1379 return input_api.os_path.splitext(file_path)[1] == ".h"
1380
1381
1382def _IsJavaFile(input_api, file_path):
1383 return input_api.os_path.splitext(file_path)[1] == ".java"
1384
1385
1386def _IsProtoFile(input_api, file_path):
1387 return input_api.os_path.splitext(file_path)[1] == ".proto"
1388
Mohamed Heikal5e5b7922020-10-29 18:57:591389
1390def CheckNoUpstreamDepsOnClank(input_api, output_api):
1391 """Prevent additions of dependencies from the upstream repo on //clank."""
1392 # clank can depend on clank
1393 if input_api.change.RepositoryRoot().endswith('clank'):
1394 return []
1395 build_file_patterns = [
1396 r'(.+/)?BUILD\.gn',
1397 r'.+\.gni',
1398 ]
1399 excluded_files = [
1400 r'build[/\\]config[/\\]android[/\\]config\.gni'
1401 ]
1402 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
1403
1404 error_message = 'Disallowed import on //clank in an upstream build file:'
1405
1406 def FilterFile(affected_file):
1407 return input_api.FilterSourceFile(
1408 affected_file,
1409 files_to_check=build_file_patterns,
1410 files_to_skip=excluded_files)
1411
1412 problems = []
1413 for f in input_api.AffectedSourceFiles(FilterFile):
1414 local_path = f.LocalPath()
1415 for line_number, line in f.ChangedContents():
1416 if (bad_pattern.search(line)):
1417 problems.append(
1418 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1419 if problems:
1420 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1421 else:
1422 return []
1423
1424
Saagar Sanghavifceeaae2020-08-12 16:40:361425def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191426 """Attempts to prevent use of functions intended only for testing in
1427 non-testing code. For now this is just a best-effort implementation
1428 that ignores header files and may have some false positives. A
1429 better implementation would probably need a proper C++ parser.
1430 """
1431 # We only scan .cc files and the like, as the declaration of
1432 # for-testing functions in header files are hard to distinguish from
1433 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491434 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191435
jochenc0d4808c2015-07-27 09:25:421436 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191437 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091438 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131439 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191440 exclusion_pattern = input_api.re.compile(
1441 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1442 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131443 # Avoid a false positive in this case, where the method name, the ::, and
1444 # the closing { are all on different lines due to line wrapping.
1445 # HelperClassForTesting::
1446 # HelperClassForTesting(
1447 # args)
1448 # : member(0) {}
1449 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191450
1451 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441452 files_to_skip = (_EXCLUDED_PATHS +
1453 _TEST_CODE_EXCLUDED_PATHS +
1454 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191455 return input_api.FilterSourceFile(
1456 affected_file,
James Cook24a504192020-07-23 00:08:441457 files_to_check=file_inclusion_pattern,
1458 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191459
1460 problems = []
1461 for f in input_api.AffectedSourceFiles(FilterFile):
1462 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131463 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241464 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031465 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461466 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131467 not exclusion_pattern.search(line) and
1468 not allowlist_pattern.search(line) and
1469 not in_method_defn):
[email protected]55459852011-08-10 15:17:191470 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031471 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131472 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191473
1474 if problems:
[email protected]f7051d52013-04-02 18:31:421475 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031476 else:
1477 return []
[email protected]55459852011-08-10 15:17:191478
1479
Saagar Sanghavifceeaae2020-08-12 16:40:361480def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231481 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591482 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231483 """
1484 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1485 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1486 name_pattern = r'ForTest(s|ing)?'
1487 # Describes an occurrence of "ForTest*" inside a // comment.
1488 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501489 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551490 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231491 # Catch calls.
1492 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1493 # Ignore definitions. (Comments are ignored separately.)
1494 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1495
1496 problems = []
1497 sources = lambda x: input_api.FilterSourceFile(
1498 x,
James Cook24a504192020-07-23 00:08:441499 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1500 + input_api.DEFAULT_FILES_TO_SKIP),
1501 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231502 )
1503 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1504 local_path = f.LocalPath()
1505 is_inside_javadoc = False
1506 for line_number, line in f.ChangedContents():
1507 if is_inside_javadoc and javadoc_end_re.search(line):
1508 is_inside_javadoc = False
1509 if not is_inside_javadoc and javadoc_start_re.search(line):
1510 is_inside_javadoc = True
1511 if is_inside_javadoc:
1512 continue
1513 if (inclusion_re.search(line) and
1514 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501515 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231516 not exclusion_re.search(line)):
1517 problems.append(
1518 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1519
1520 if problems:
1521 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1522 else:
1523 return []
1524
1525
Saagar Sanghavifceeaae2020-08-12 16:40:361526def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541527 """Checks to make sure no .h files include <iostream>."""
1528 files = []
1529 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1530 input_api.re.MULTILINE)
1531 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1532 if not f.LocalPath().endswith('.h'):
1533 continue
1534 contents = input_api.ReadFile(f)
1535 if pattern.search(contents):
1536 files.append(f)
1537
1538 if len(files):
yolandyandaabc6d2016-04-18 18:29:391539 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061540 'Do not #include <iostream> in header files, since it inserts static '
1541 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541542 '#include <ostream>. See http://crbug.com/94794',
1543 files) ]
1544 return []
1545
Danil Chapovalov3518f362018-08-11 16:13:431546def _CheckNoStrCatRedefines(input_api, output_api):
1547 """Checks no windows headers with StrCat redefined are included directly."""
1548 files = []
1549 pattern_deny = input_api.re.compile(
1550 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1551 input_api.re.MULTILINE)
1552 pattern_allow = input_api.re.compile(
1553 r'^#include\s"base/win/windows_defines.inc"',
1554 input_api.re.MULTILINE)
1555 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1556 contents = input_api.ReadFile(f)
1557 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1558 files.append(f.LocalPath())
1559
1560 if len(files):
1561 return [output_api.PresubmitError(
1562 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1563 'directly since they pollute code with StrCat macro. Instead, '
1564 'include matching header from base/win. See http://crbug.com/856536',
1565 files) ]
1566 return []
1567
[email protected]10689ca2011-09-02 02:31:541568
Saagar Sanghavifceeaae2020-08-12 16:40:361569def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521570 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181571 problems = []
1572 for f in input_api.AffectedFiles():
1573 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1574 continue
1575
1576 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041577 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181578 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1579
1580 if not problems:
1581 return []
1582 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1583 '\n'.join(problems))]
1584
Saagar Sanghavifceeaae2020-08-12 16:40:361585def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341586 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1587
1588 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1589 instead of DISABLED_. To filter false positives, reports are only generated
1590 if a corresponding MAYBE_ line exists.
1591 """
1592 problems = []
1593
1594 # The following two patterns are looked for in tandem - is a test labeled
1595 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1596 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1597 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1598
1599 # This is for the case that a test is disabled on all platforms.
1600 full_disable_pattern = input_api.re.compile(
1601 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1602 input_api.re.MULTILINE)
1603
Katie Df13948e2018-09-25 07:33:441604 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341605 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1606 continue
1607
1608 # Search for MABYE_, DISABLE_ pairs.
1609 disable_lines = {} # Maps of test name to line number.
1610 maybe_lines = {}
1611 for line_num, line in f.ChangedContents():
1612 disable_match = disable_pattern.search(line)
1613 if disable_match:
1614 disable_lines[disable_match.group(1)] = line_num
1615 maybe_match = maybe_pattern.search(line)
1616 if maybe_match:
1617 maybe_lines[maybe_match.group(1)] = line_num
1618
1619 # Search for DISABLE_ occurrences within a TEST() macro.
1620 disable_tests = set(disable_lines.keys())
1621 maybe_tests = set(maybe_lines.keys())
1622 for test in disable_tests.intersection(maybe_tests):
1623 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1624
1625 contents = input_api.ReadFile(f)
1626 full_disable_match = full_disable_pattern.search(contents)
1627 if full_disable_match:
1628 problems.append(' %s' % f.LocalPath())
1629
1630 if not problems:
1631 return []
1632 return [
1633 output_api.PresubmitPromptWarning(
1634 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1635 '\n'.join(problems))
1636 ]
1637
[email protected]72df4e782012-06-21 16:28:181638
Saagar Sanghavifceeaae2020-08-12 16:40:361639def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571640 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521641 errors = []
Hans Wennborg944479f2020-06-25 21:39:251642 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521643 input_api.re.MULTILINE)
1644 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1645 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1646 continue
1647 for lnum, line in f.ChangedContents():
1648 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171649 errors.append(output_api.PresubmitError(
1650 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571651 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171652 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521653 return errors
1654
1655
Weilun Shia487fad2020-10-28 00:10:341656# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1657# more reliable way. See
1658# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191659
wnwenbdc444e2016-05-25 13:44:151660
Saagar Sanghavifceeaae2020-08-12 16:40:361661def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391662 """Check that FlakyTest annotation is our own instead of the android one"""
1663 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1664 files = []
1665 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1666 if f.LocalPath().endswith('Test.java'):
1667 if pattern.search(input_api.ReadFile(f)):
1668 files.append(f)
1669 if len(files):
1670 return [output_api.PresubmitError(
1671 'Use org.chromium.base.test.util.FlakyTest instead of '
1672 'android.test.FlakyTest',
1673 files)]
1674 return []
mcasasb7440c282015-02-04 14:52:191675
wnwenbdc444e2016-05-25 13:44:151676
Saagar Sanghavifceeaae2020-08-12 16:40:361677def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441678 """Make sure .DEPS.git is never modified manually."""
1679 if any(f.LocalPath().endswith('.DEPS.git') for f in
1680 input_api.AffectedFiles()):
1681 return [output_api.PresubmitError(
1682 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1683 'automated system based on what\'s in DEPS and your changes will be\n'
1684 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501685 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1686 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441687 'for more information')]
1688 return []
1689
1690
Saagar Sanghavifceeaae2020-08-12 16:40:361691def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471692 """Checks that DEPS file deps are from allowed_hosts."""
1693 # Run only if DEPS file has been modified to annoy fewer bystanders.
1694 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1695 return []
1696 # Outsource work to gclient verify
1697 try:
John Budorickf20c0042019-04-25 23:23:401698 gclient_path = input_api.os_path.join(
1699 input_api.PresubmitLocalPath(),
1700 'third_party', 'depot_tools', 'gclient.py')
1701 input_api.subprocess.check_output(
1702 [input_api.python_executable, gclient_path, 'verify'],
1703 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471704 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201705 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471706 return [output_api.PresubmitError(
1707 'DEPS file must have only git dependencies.',
1708 long_text=error.output)]
1709
1710
Mario Sanchez Prada2472cab2019-09-18 10:58:311711def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1712 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591713 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311714
1715 Returns an string composed of the name of the file, the line number where the
1716 match has been found and the additional text passed as |message| in case the
1717 target type name matches the text inside the line passed as parameter.
1718 """
Peng Huang9c5949a02020-06-11 19:20:541719 result = []
1720
danakjd18e8892020-12-17 17:42:011721 if input_api.re.search(r"^ *//", line): # Ignore comments about banned types.
1722 return result
1723 if line.endswith(" nocheck"): # A // nocheck comment will bypass this error.
Peng Huang9c5949a02020-06-11 19:20:541724 return result
1725
Mario Sanchez Prada2472cab2019-09-18 10:58:311726 matched = False
1727 if type_name[0:1] == '/':
1728 regex = type_name[1:]
1729 if input_api.re.search(regex, line):
1730 matched = True
1731 elif type_name in line:
1732 matched = True
1733
Mario Sanchez Prada2472cab2019-09-18 10:58:311734 if matched:
1735 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1736 for message_line in message:
1737 result.append(' %s' % message_line)
1738
1739 return result
1740
1741
Saagar Sanghavifceeaae2020-08-12 16:40:361742def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591743 """Make sure that banned functions are not used."""
1744 warnings = []
1745 errors = []
1746
James Cook24a504192020-07-23 00:08:441747 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151748 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441749 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151750 if input_api.re.match(item, local_path):
1751 return True
1752 return False
1753
Peter K. Lee6c03ccff2019-07-15 14:40:051754 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541755 local_path = affected_file.LocalPath()
1756 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1757 return False
1758 basename = input_api.os_path.basename(local_path)
1759 if 'ios' in basename.split('_'):
1760 return True
1761 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1762 if sep and 'ios' in local_path.split(sep):
1763 return True
1764 return False
1765
wnwenbdc444e2016-05-25 13:44:151766 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311767 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1768 func_name, message)
1769 if problems:
wnwenbdc444e2016-05-25 13:44:151770 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311771 errors.extend(problems)
1772 else:
1773 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151774
Eric Stevensona9a980972017-09-23 00:04:411775 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1776 for f in input_api.AffectedFiles(file_filter=file_filter):
1777 for line_num, line in f.ChangedContents():
1778 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1779 CheckForMatch(f, line_num, line, func_name, message, error)
1780
[email protected]127f18ec2012-06-16 05:05:591781 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1782 for f in input_api.AffectedFiles(file_filter=file_filter):
1783 for line_num, line in f.ChangedContents():
1784 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151785 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591786
Peter K. Lee6c03ccff2019-07-15 14:40:051787 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541788 for line_num, line in f.ChangedContents():
1789 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1790 CheckForMatch(f, line_num, line, func_name, message, error)
1791
Peter K. Lee6c03ccff2019-07-15 14:40:051792 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1793 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1794 for line_num, line in f.ChangedContents():
1795 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1796 CheckForMatch(f, line_num, line, func_name, message, error)
1797
[email protected]127f18ec2012-06-16 05:05:591798 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1799 for f in input_api.AffectedFiles(file_filter=file_filter):
1800 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491801 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441802 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491803 continue
wnwenbdc444e2016-05-25 13:44:151804 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591805
1806 result = []
1807 if (warnings):
1808 result.append(output_api.PresubmitPromptWarning(
1809 'Banned functions were used.\n' + '\n'.join(warnings)))
1810 if (errors):
1811 result.append(output_api.PresubmitError(
1812 'Banned functions were used.\n' + '\n'.join(errors)))
1813 return result
1814
1815
Michael Thiessen44457642020-02-06 00:24:151816def _CheckAndroidNoBannedImports(input_api, output_api):
1817 """Make sure that banned java imports are not used."""
1818 errors = []
1819
1820 def IsException(path, exceptions):
1821 for exception in exceptions:
1822 if (path.startswith(exception)):
1823 return True
1824 return False
1825
1826 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1827 for f in input_api.AffectedFiles(file_filter=file_filter):
1828 for line_num, line in f.ChangedContents():
1829 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1830 if IsException(f.LocalPath(), exceptions):
1831 continue;
1832 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1833 'import ' + import_name, message)
1834 if problems:
1835 errors.extend(problems)
1836 result = []
1837 if (errors):
1838 result.append(output_api.PresubmitError(
1839 'Banned imports were used.\n' + '\n'.join(errors)))
1840 return result
1841
1842
Saagar Sanghavifceeaae2020-08-12 16:40:361843def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311844 """Make sure that old Mojo types are not used."""
1845 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571846 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311847
Mario Sanchez Pradaaab91382019-12-19 08:57:091848 # For any path that is not an "ok" or an "error" path, a warning will be
1849 # raised if deprecated mojo types are found.
1850 ok_paths = ['components/arc']
1851 error_paths = ['third_party/blink', 'content']
1852
Mario Sanchez Prada2472cab2019-09-18 10:58:311853 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1854 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571855 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091856 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311857 continue
1858
1859 for line_num, line in f.ChangedContents():
1860 for func_name, message in _DEPRECATED_MOJO_TYPES:
1861 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1862 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571863
Mario Sanchez Prada2472cab2019-09-18 10:58:311864 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091865 # Raise errors inside |error_paths| and warnings everywhere else.
1866 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571867 errors.extend(problems)
1868 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:311869 warnings.extend(problems)
1870
1871 result = []
1872 if (warnings):
1873 result.append(output_api.PresubmitPromptWarning(
1874 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:571875 if (errors):
1876 result.append(output_api.PresubmitError(
1877 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:311878 return result
1879
1880
Saagar Sanghavifceeaae2020-08-12 16:40:361881def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:061882 """Make sure that banned functions are not used."""
1883 files = []
1884 pattern = input_api.re.compile(r'^#pragma\s+once',
1885 input_api.re.MULTILINE)
1886 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1887 if not f.LocalPath().endswith('.h'):
1888 continue
1889 contents = input_api.ReadFile(f)
1890 if pattern.search(contents):
1891 files.append(f)
1892
1893 if files:
1894 return [output_api.PresubmitError(
1895 'Do not use #pragma once in header files.\n'
1896 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1897 files)]
1898 return []
1899
[email protected]127f18ec2012-06-16 05:05:591900
Saagar Sanghavifceeaae2020-08-12 16:40:361901def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:121902 """Checks to make sure we don't introduce use of foo ? true : false."""
1903 problems = []
1904 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1905 for f in input_api.AffectedFiles():
1906 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1907 continue
1908
1909 for line_num, line in f.ChangedContents():
1910 if pattern.match(line):
1911 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1912
1913 if not problems:
1914 return []
1915 return [output_api.PresubmitPromptWarning(
1916 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1917 '\n'.join(problems))]
1918
1919
Saagar Sanghavifceeaae2020-08-12 16:40:361920def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281921 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181922 change. Breaking - rules is an error, breaking ! rules is a
1923 warning.
1924 """
mohan.reddyf21db962014-10-16 12:26:471925 import sys
[email protected]55f9f382012-07-31 11:02:181926 # We need to wait until we have an input_api object and use this
1927 # roundabout construct to import checkdeps because this file is
1928 # eval-ed and thus doesn't have __file__.
1929 original_sys_path = sys.path
1930 try:
1931 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471932 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181933 import checkdeps
[email protected]55f9f382012-07-31 11:02:181934 from rules import Rule
1935 finally:
1936 # Restore sys.path to what it was before.
1937 sys.path = original_sys_path
1938
1939 added_includes = []
rhalavati08acd232017-04-03 07:23:281940 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241941 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181942 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061943 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501944 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081945 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061946 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501947 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081948 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061949 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501950 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081951 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181952
[email protected]26385172013-05-09 23:11:351953 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181954
1955 error_descriptions = []
1956 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281957 error_subjects = set()
1958 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:361959
[email protected]55f9f382012-07-31 11:02:181960 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1961 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081962 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181963 description_with_path = '%s\n %s' % (path, rule_description)
1964 if rule_type == Rule.DISALLOW:
1965 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281966 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181967 else:
1968 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281969 warning_subjects.add("#includes")
1970
1971 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1972 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081973 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281974 description_with_path = '%s\n %s' % (path, rule_description)
1975 if rule_type == Rule.DISALLOW:
1976 error_descriptions.append(description_with_path)
1977 error_subjects.add("imports")
1978 else:
1979 warning_descriptions.append(description_with_path)
1980 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181981
Jinsuk Kim5a092672017-10-24 22:42:241982 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021983 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081984 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241985 description_with_path = '%s\n %s' % (path, rule_description)
1986 if rule_type == Rule.DISALLOW:
1987 error_descriptions.append(description_with_path)
1988 error_subjects.add("imports")
1989 else:
1990 warning_descriptions.append(description_with_path)
1991 warning_subjects.add("imports")
1992
[email protected]55f9f382012-07-31 11:02:181993 results = []
1994 if error_descriptions:
1995 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281996 'You added one or more %s that violate checkdeps rules.'
1997 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181998 error_descriptions))
1999 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422000 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282001 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182002 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282003 '%s? See relevant DEPS file(s) for details and contacts.' %
2004 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182005 warning_descriptions))
2006 return results
2007
2008
Saagar Sanghavifceeaae2020-08-12 16:40:362009def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222010 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152011 if input_api.platform == 'win32':
2012 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292013 checkperms_tool = input_api.os_path.join(
2014 input_api.PresubmitLocalPath(),
2015 'tools', 'checkperms', 'checkperms.py')
2016 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472017 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392018 with input_api.CreateTemporaryFile() as file_list:
2019 for f in input_api.AffectedFiles():
2020 # checkperms.py file/directory arguments must be relative to the
2021 # repository.
2022 file_list.write(f.LocalPath() + '\n')
2023 file_list.close()
2024 args += ['--file-list', file_list.name]
2025 try:
2026 input_api.subprocess.check_output(args)
2027 return []
2028 except input_api.subprocess.CalledProcessError as error:
2029 return [output_api.PresubmitError(
2030 'checkperms.py failed:',
2031 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222032
2033
Saagar Sanghavifceeaae2020-08-12 16:40:362034def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492035 """Makes sure we don't include ui/aura/window_property.h
2036 in header files.
2037 """
2038 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2039 errors = []
2040 for f in input_api.AffectedFiles():
2041 if not f.LocalPath().endswith('.h'):
2042 continue
2043 for line_num, line in f.ChangedContents():
2044 if pattern.match(line):
2045 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2046
2047 results = []
2048 if errors:
2049 results.append(output_api.PresubmitError(
2050 'Header files should not include ui/aura/window_property.h', errors))
2051 return results
2052
2053
[email protected]70ca77752012-11-20 03:45:032054def _CheckForVersionControlConflictsInFile(input_api, f):
2055 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2056 errors = []
2057 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162058 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232059 # First-level headers in markdown look a lot like version control
2060 # conflict markers. http://daringfireball.net/projects/markdown/basics
2061 continue
[email protected]70ca77752012-11-20 03:45:032062 if pattern.match(line):
2063 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2064 return errors
2065
2066
Saagar Sanghavifceeaae2020-08-12 16:40:362067def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032068 """Usually this is not intentional and will cause a compile failure."""
2069 errors = []
2070 for f in input_api.AffectedFiles():
2071 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2072
2073 results = []
2074 if errors:
2075 results.append(output_api.PresubmitError(
2076 'Version control conflict markers found, please resolve.', errors))
2077 return results
2078
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202079
Saagar Sanghavifceeaae2020-08-12 16:40:362080def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162081 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2082 errors = []
2083 for f in input_api.AffectedFiles():
2084 for line_num, line in f.ChangedContents():
2085 if pattern.search(line):
2086 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2087
2088 results = []
2089 if errors:
2090 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502091 'Found Google support URL addressed by answer number. Please replace '
2092 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162093 return results
2094
[email protected]70ca77752012-11-20 03:45:032095
Saagar Sanghavifceeaae2020-08-12 16:40:362096def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442097 def FilterFile(affected_file):
2098 """Filter function for use with input_api.AffectedSourceFiles,
2099 below. This filters out everything except non-test files from
2100 top-level directories that generally speaking should not hard-code
2101 service URLs (e.g. src/android_webview/, src/content/ and others).
2102 """
2103 return input_api.FilterSourceFile(
2104 affected_file,
James Cook24a504192020-07-23 00:08:442105 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2106 files_to_skip=(_EXCLUDED_PATHS +
2107 _TEST_CODE_EXCLUDED_PATHS +
2108 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442109
reillyi38965732015-11-16 18:27:332110 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2111 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462112 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2113 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442114 problems = [] # items are (filename, line_number, line)
2115 for f in input_api.AffectedSourceFiles(FilterFile):
2116 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462117 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442118 problems.append((f.LocalPath(), line_num, line))
2119
2120 if problems:
[email protected]f7051d52013-04-02 18:31:422121 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442122 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582123 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442124 [' %s:%d: %s' % (
2125 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032126 else:
2127 return []
[email protected]06e6d0ff2012-12-11 01:36:442128
2129
Saagar Sanghavifceeaae2020-08-12 16:40:362130def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292131 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2132 def FileFilter(affected_file):
2133 """Includes directories known to be Chrome OS only."""
2134 return input_api.FilterSourceFile(
2135 affected_file,
James Cook24a504192020-07-23 00:08:442136 files_to_check=('^ash/',
2137 '^chromeos/', # Top-level src/chromeos.
2138 '/chromeos/', # Any path component.
2139 '^components/arc',
2140 '^components/exo'),
2141 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292142
2143 prefs = []
2144 priority_prefs = []
2145 for f in input_api.AffectedFiles(file_filter=FileFilter):
2146 for line_num, line in f.ChangedContents():
2147 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2148 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2149 prefs.append(' %s' % line)
2150 if input_api.re.search(
2151 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2152 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2153 priority_prefs.append(' %s' % line)
2154
2155 results = []
2156 if (prefs):
2157 results.append(output_api.PresubmitPromptWarning(
2158 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2159 'by browser sync settings. If these prefs should be controlled by OS '
2160 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2161 if (priority_prefs):
2162 results.append(output_api.PresubmitPromptWarning(
2163 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2164 'controlled by browser sync settings. If these prefs should be '
2165 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2166 'instead.\n' + '\n'.join(prefs)))
2167 return results
2168
2169
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492170# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362171def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272172 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312173 The native_client_sdk directory is excluded because it has auto-generated PNG
2174 files for documentation.
[email protected]d2530012013-01-25 16:39:272175 """
[email protected]d2530012013-01-25 16:39:272176 errors = []
James Cook24a504192020-07-23 00:08:442177 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2178 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312179 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442180 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312181 for f in input_api.AffectedFiles(include_deletes=False,
2182 file_filter=file_filter):
2183 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272184
2185 results = []
2186 if errors:
2187 results.append(output_api.PresubmitError(
2188 'The name of PNG files should not have abbreviations. \n'
2189 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2190 'Contact [email protected] if you have questions.', errors))
2191 return results
2192
2193
Daniel Cheng4dcdb6b2017-04-13 08:30:172194def _ExtractAddRulesFromParsedDeps(parsed_deps):
2195 """Extract the rules that add dependencies from a parsed DEPS file.
2196
2197 Args:
2198 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2199 add_rules = set()
2200 add_rules.update([
2201 rule[1:] for rule in parsed_deps.get('include_rules', [])
2202 if rule.startswith('+') or rule.startswith('!')
2203 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502204 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172205 {}).iteritems():
2206 add_rules.update([
2207 rule[1:] for rule in rules
2208 if rule.startswith('+') or rule.startswith('!')
2209 ])
2210 return add_rules
2211
2212
2213def _ParseDeps(contents):
2214 """Simple helper for parsing DEPS files."""
2215 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172216 class _VarImpl:
2217
2218 def __init__(self, local_scope):
2219 self._local_scope = local_scope
2220
2221 def Lookup(self, var_name):
2222 """Implements the Var syntax."""
2223 try:
2224 return self._local_scope['vars'][var_name]
2225 except KeyError:
2226 raise Exception('Var is not defined: %s' % var_name)
2227
2228 local_scope = {}
2229 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172230 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592231 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172232 }
2233 exec contents in global_scope, local_scope
2234 return local_scope
2235
2236
2237def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592238 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412239 a set of DEPS entries that we should look up.
2240
2241 For a directory (rather than a specific filename) we fake a path to
2242 a specific filename by adding /DEPS. This is chosen as a file that
2243 will seldom or never be subject to per-file include_rules.
2244 """
[email protected]2b438d62013-11-14 17:54:142245 # We ignore deps entries on auto-generated directories.
2246 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082247
Daniel Cheng4dcdb6b2017-04-13 08:30:172248 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2249 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2250
2251 added_deps = new_deps.difference(old_deps)
2252
[email protected]2b438d62013-11-14 17:54:142253 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172254 for added_dep in added_deps:
2255 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2256 continue
2257 # Assume that a rule that ends in .h is a rule for a specific file.
2258 if added_dep.endswith('.h'):
2259 results.add(added_dep)
2260 else:
2261 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082262 return results
2263
2264
Saagar Sanghavifceeaae2020-08-12 16:40:362265def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552266 """When a dependency prefixed with + is added to a DEPS file, we
2267 want to make sure that the change is reviewed by an OWNER of the
2268 target file or directory, to avoid layering violations from being
2269 introduced. This check verifies that this happens.
2270 """
Joey Mou57048132021-02-26 22:17:552271 # We rely on Gerrit's code-owners to check approvals.
2272 # input_api.gerrit is always set for Chromium, but other projects
2273 # might not use Gerrit.
2274 if not input_api.gerrit:
2275 return []
Edward Lesmes44feb2332021-03-19 01:27:522276 if (input_api.change.issue and
2277 input_api.gerrit.IsOwnersOverrideApproved(input_api.change.issue)):
Edward Lesmes6fba51082021-01-20 04:20:232278 # Skip OWNERS check when Owners-Override label is approved. This is intended
2279 # for global owners, trusted bots, and on-call sheriffs. Review is still
2280 # required for these changes.
Edward Lesmes44feb2332021-03-19 01:27:522281 return []
Edward Lesmes6fba51082021-01-20 04:20:232282
Daniel Cheng4dcdb6b2017-04-13 08:30:172283 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242284
2285 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492286 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242287 for f in input_api.AffectedFiles(include_deletes=False,
2288 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552289 filename = input_api.os_path.basename(f.LocalPath())
2290 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172291 virtual_depended_on_files.update(_CalculateAddedDeps(
2292 input_api.os_path,
2293 '\n'.join(f.OldContents()),
2294 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552295
[email protected]e871964c2013-05-13 14:14:552296 if not virtual_depended_on_files:
2297 return []
2298
2299 if input_api.is_committing:
2300 if input_api.tbr:
2301 return [output_api.PresubmitNotifyResult(
2302 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272303 if input_api.dry_run:
2304 return [output_api.PresubmitNotifyResult(
2305 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552306 if not input_api.change.issue:
2307 return [output_api.PresubmitError(
2308 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402309 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552310 output = output_api.PresubmitError
2311 else:
2312 output = output_api.PresubmitNotifyResult
2313
tandriied3b7e12016-05-12 14:38:502314 owner_email, reviewers = (
2315 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2316 input_api,
Edward Lesmesa3846442021-02-08 20:20:032317 None,
tandriied3b7e12016-05-12 14:38:502318 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552319
2320 owner_email = owner_email or input_api.change.author_email
2321
Edward Lesmesa3846442021-02-08 20:20:032322 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2323 virtual_depended_on_files, reviewers.union([owner_email]), [])
2324 missing_files = [
2325 f for f in virtual_depended_on_files
2326 if approval_status[f] != input_api.owners_client.APPROVED]
[email protected]14a6131c2014-01-08 01:15:412327
2328 # We strip the /DEPS part that was added by
2329 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2330 # directory.
2331 def StripDeps(path):
2332 start_deps = path.rfind('/DEPS')
2333 if start_deps != -1:
2334 return path[:start_deps]
2335 else:
2336 return path
2337 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552338 for path in missing_files]
2339
2340 if unapproved_dependencies:
2341 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152342 output('You need LGTM from owners of depends-on paths in DEPS that were '
2343 'modified in this CL:\n %s' %
2344 '\n '.join(sorted(unapproved_dependencies)))]
Edward Lesmesa3846442021-02-08 20:20:032345 suggested_owners = input_api.owners_client.SuggestOwners(
2346 missing_files, exclude=[owner_email])
Paweł Hajdan, Jrec17f882016-07-04 14:16:152347 output_list.append(output(
2348 'Suggested missing target path OWNERS:\n %s' %
2349 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552350 return output_list
2351
2352 return []
2353
2354
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492355# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362356def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492357 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442358 files_to_skip = (_EXCLUDED_PATHS +
2359 _TEST_CODE_EXCLUDED_PATHS +
2360 input_api.DEFAULT_FILES_TO_SKIP +
2361 (r"^base[\\/]logging\.h$",
2362 r"^base[\\/]logging\.cc$",
2363 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2364 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2365 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2366 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2367 r"startup_browser_creator\.cc$",
2368 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2369 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2370 r"diagnostics_writer\.cc$",
2371 r"^chrome[\\/]chrome_cleaner[\\/].*",
2372 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2373 r"dll_hash_main\.cc$",
2374 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2375 r"^chromecast[\\/]",
2376 r"^cloud_print[\\/]",
2377 r"^components[\\/]browser_watcher[\\/]"
2378 r"dump_stability_report_main_win.cc$",
2379 r"^components[\\/]media_control[\\/]renderer[\\/]"
2380 r"media_playback_options\.cc$",
ziyangch5f89c4a62021-02-26 19:57:352381 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2382 r"overlay_strategy_underlay_cast\.cc$",
James Cook24a504192020-07-23 00:08:442383 r"^components[\\/]zucchini[\\/].*",
2384 # TODO(peter): Remove exception. https://crbug.com/534537
2385 r"^content[\\/]browser[\\/]notifications[\\/]"
2386 r"notification_event_dispatcher_impl\.cc$",
2387 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2388 r"gl_helper_benchmark\.cc$",
2389 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2390 r"^courgette[\\/]courgette_tool\.cc$",
2391 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2392 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2393 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
Fabrice de Gans-Riberi1d4c7ee2021-03-10 21:24:082394 # TODO(https://crbug.com/1181062): Temporary debugging.
Alexei Svitkine64505a92021-03-11 22:00:542395 r"^fuchsia[\\/]engine[\\/]renderer[\\/]"
2396 r"web_engine_render_frame_observer.cc$",
James Cook24a504192020-07-23 00:08:442397 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2398 r"^ipc[\\/]ipc_logging\.cc$",
2399 r"^native_client_sdk[\\/]",
2400 r"^remoting[\\/]base[\\/]logging\.h$",
2401 r"^remoting[\\/]host[\\/].*",
2402 r"^sandbox[\\/]linux[\\/].*",
2403 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2404 r"dump_file_system.cc$",
2405 r"^tools[\\/]",
2406 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2407 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2408 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2409 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2410 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402411 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442412 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402413
thomasanderson625d3932017-03-29 07:16:582414 log_info = set([])
2415 printf = set([])
[email protected]85218562013-11-22 07:41:402416
2417 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582418 for _, line in f.ChangedContents():
2419 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2420 log_info.add(f.LocalPath())
2421 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2422 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372423
thomasanderson625d3932017-03-29 07:16:582424 if input_api.re.search(r"\bprintf\(", line):
2425 printf.add(f.LocalPath())
2426 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2427 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402428
2429 if log_info:
2430 return [output_api.PresubmitError(
2431 'These files spam the console log with LOG(INFO):',
2432 items=log_info)]
2433 if printf:
2434 return [output_api.PresubmitError(
2435 'These files spam the console log with printf/fprintf:',
2436 items=printf)]
2437 return []
2438
2439
Saagar Sanghavifceeaae2020-08-12 16:40:362440def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162441 """These types are all expected to hold locks while in scope and
2442 so should never be anonymous (which causes them to be immediately
2443 destroyed)."""
2444 they_who_must_be_named = [
2445 'base::AutoLock',
2446 'base::AutoReset',
2447 'base::AutoUnlock',
2448 'SkAutoAlphaRestore',
2449 'SkAutoBitmapShaderInstall',
2450 'SkAutoBlitterChoose',
2451 'SkAutoBounderCommit',
2452 'SkAutoCallProc',
2453 'SkAutoCanvasRestore',
2454 'SkAutoCommentBlock',
2455 'SkAutoDescriptor',
2456 'SkAutoDisableDirectionCheck',
2457 'SkAutoDisableOvalCheck',
2458 'SkAutoFree',
2459 'SkAutoGlyphCache',
2460 'SkAutoHDC',
2461 'SkAutoLockColors',
2462 'SkAutoLockPixels',
2463 'SkAutoMalloc',
2464 'SkAutoMaskFreeImage',
2465 'SkAutoMutexAcquire',
2466 'SkAutoPathBoundsUpdate',
2467 'SkAutoPDFRelease',
2468 'SkAutoRasterClipValidate',
2469 'SkAutoRef',
2470 'SkAutoTime',
2471 'SkAutoTrace',
2472 'SkAutoUnref',
2473 ]
2474 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2475 # bad: base::AutoLock(lock.get());
2476 # not bad: base::AutoLock lock(lock.get());
2477 bad_pattern = input_api.re.compile(anonymous)
2478 # good: new base::AutoLock(lock.get())
2479 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2480 errors = []
2481
2482 for f in input_api.AffectedFiles():
2483 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2484 continue
2485 for linenum, line in f.ChangedContents():
2486 if bad_pattern.search(line) and not good_pattern.search(line):
2487 errors.append('%s:%d' % (f.LocalPath(), linenum))
2488
2489 if errors:
2490 return [output_api.PresubmitError(
2491 'These lines create anonymous variables that need to be named:',
2492 items=errors)]
2493 return []
2494
2495
Saagar Sanghavifceeaae2020-08-12 16:40:362496def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532497 # Returns whether |template_str| is of the form <T, U...> for some types T
2498 # and U. Assumes that |template_str| is already in the form <...>.
2499 def HasMoreThanOneArg(template_str):
2500 # Level of <...> nesting.
2501 nesting = 0
2502 for c in template_str:
2503 if c == '<':
2504 nesting += 1
2505 elif c == '>':
2506 nesting -= 1
2507 elif c == ',' and nesting == 1:
2508 return True
2509 return False
2510
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492511 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102512 sources = lambda affected_file: input_api.FilterSourceFile(
2513 affected_file,
James Cook24a504192020-07-23 00:08:442514 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2515 input_api.DEFAULT_FILES_TO_SKIP),
2516 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552517
2518 # Pattern to capture a single "<...>" block of template arguments. It can
2519 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2520 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2521 # latter would likely require counting that < and > match, which is not
2522 # expressible in regular languages. Should the need arise, one can introduce
2523 # limited counting (matching up to a total number of nesting depth), which
2524 # should cover all practical cases for already a low nesting limit.
2525 template_arg_pattern = (
2526 r'<[^>]*' # Opening block of <.
2527 r'>([^<]*>)?') # Closing block of >.
2528 # Prefix expressing that whatever follows is not already inside a <...>
2529 # block.
2530 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102531 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552532 not_inside_template_arg_pattern
2533 + r'\bstd::unique_ptr'
2534 + template_arg_pattern
2535 + r'\(\)')
2536
2537 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2538 template_arg_no_array_pattern = (
2539 r'<[^>]*[^]]' # Opening block of <.
2540 r'>([^(<]*[^]]>)?') # Closing block of >.
2541 # Prefix saying that what follows is the start of an expression.
2542 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2543 # Suffix saying that what follows are call parentheses with a non-empty list
2544 # of arguments.
2545 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532546 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552547 return_construct_pattern = input_api.re.compile(
2548 start_of_expr_pattern
2549 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532550 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552551 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532552 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552553 + nonempty_arg_list_pattern)
2554
Vaclav Brozek851d9602018-04-04 16:13:052555 problems_constructor = []
2556 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102557 for f in input_api.AffectedSourceFiles(sources):
2558 for line_number, line in f.ChangedContents():
2559 # Disallow:
2560 # return std::unique_ptr<T>(foo);
2561 # bar = std::unique_ptr<T>(foo);
2562 # But allow:
2563 # return std::unique_ptr<T[]>(foo);
2564 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532565 # And also allow cases when the second template argument is present. Those
2566 # cases cannot be handled by std::make_unique:
2567 # return std::unique_ptr<T, U>(foo);
2568 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052569 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532570 return_construct_result = return_construct_pattern.search(line)
2571 if return_construct_result and not HasMoreThanOneArg(
2572 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052573 problems_constructor.append(
2574 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102575 # Disallow:
2576 # std::unique_ptr<T>()
2577 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052578 problems_nullptr.append(
2579 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2580
2581 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162582 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052583 errors.append(output_api.PresubmitError(
2584 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162585 problems_nullptr))
2586 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052587 errors.append(output_api.PresubmitError(
2588 'The following files use explicit std::unique_ptr constructor.'
2589 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162590 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102591 return errors
2592
2593
Saagar Sanghavifceeaae2020-08-12 16:40:362594def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082595 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522596 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082597 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522598 # If actions.xml is already included in the changelist, the PRESUBMIT
2599 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082600 return []
2601
Alexei Svitkine64505a92021-03-11 22:00:542602 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2603 files_to_skip = (_EXCLUDED_PATHS +
2604 _TEST_CODE_EXCLUDED_PATHS +
2605 input_api.DEFAULT_FILES_TO_SKIP )
2606 file_filter = lambda f: input_api.FilterSourceFile(
2607 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2608
[email protected]999261d2014-03-03 20:08:082609 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522610 current_actions = None
[email protected]999261d2014-03-03 20:08:082611 for f in input_api.AffectedFiles(file_filter=file_filter):
2612 for line_num, line in f.ChangedContents():
2613 match = input_api.re.search(action_re, line)
2614 if match:
[email protected]2f92dec2014-03-07 19:21:522615 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2616 # loaded only once.
2617 if not current_actions:
2618 with open('tools/metrics/actions/actions.xml') as actions_f:
2619 current_actions = actions_f.read()
2620 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082621 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522622 action = 'name="{0}"'.format(action_name)
2623 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082624 return [output_api.PresubmitPromptWarning(
2625 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522626 'tools/metrics/actions/actions.xml. Please run '
2627 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082628 % (f.LocalPath(), line_num, action_name))]
2629 return []
2630
2631
Daniel Cheng13ca61a882017-08-25 15:11:252632def _ImportJSONCommentEater(input_api):
2633 import sys
2634 sys.path = sys.path + [input_api.os_path.join(
2635 input_api.PresubmitLocalPath(),
2636 'tools', 'json_comment_eater')]
2637 import json_comment_eater
2638 return json_comment_eater
2639
2640
[email protected]99171a92014-06-03 08:44:472641def _GetJSONParseError(input_api, filename, eat_comments=True):
2642 try:
2643 contents = input_api.ReadFile(filename)
2644 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252645 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132646 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472647
2648 input_api.json.loads(contents)
2649 except ValueError as e:
2650 return e
2651 return None
2652
2653
2654def _GetIDLParseError(input_api, filename):
2655 try:
2656 contents = input_api.ReadFile(filename)
2657 idl_schema = input_api.os_path.join(
2658 input_api.PresubmitLocalPath(),
2659 'tools', 'json_schema_compiler', 'idl_schema.py')
2660 process = input_api.subprocess.Popen(
2661 [input_api.python_executable, idl_schema],
2662 stdin=input_api.subprocess.PIPE,
2663 stdout=input_api.subprocess.PIPE,
2664 stderr=input_api.subprocess.PIPE,
2665 universal_newlines=True)
2666 (_, error) = process.communicate(input=contents)
2667 return error or None
2668 except ValueError as e:
2669 return e
2670
2671
Saagar Sanghavifceeaae2020-08-12 16:40:362672def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472673 """Check that IDL and JSON files do not contain syntax errors."""
2674 actions = {
2675 '.idl': _GetIDLParseError,
2676 '.json': _GetJSONParseError,
2677 }
[email protected]99171a92014-06-03 08:44:472678 # Most JSON files are preprocessed and support comments, but these do not.
2679 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042680 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472681 ]
2682 # Only run IDL checker on files in these directories.
2683 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042684 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2685 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472686 ]
2687
2688 def get_action(affected_file):
2689 filename = affected_file.LocalPath()
2690 return actions.get(input_api.os_path.splitext(filename)[1])
2691
[email protected]99171a92014-06-03 08:44:472692 def FilterFile(affected_file):
2693 action = get_action(affected_file)
2694 if not action:
2695 return False
2696 path = affected_file.LocalPath()
2697
Erik Staab2dd72b12020-04-16 15:03:402698 if _MatchesFile(input_api,
2699 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2700 path):
[email protected]99171a92014-06-03 08:44:472701 return False
2702
2703 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162704 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472705 return False
2706 return True
2707
2708 results = []
2709 for affected_file in input_api.AffectedFiles(
2710 file_filter=FilterFile, include_deletes=False):
2711 action = get_action(affected_file)
2712 kwargs = {}
2713 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162714 _MatchesFile(input_api, json_no_comments_patterns,
2715 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472716 kwargs['eat_comments'] = False
2717 parse_error = action(input_api,
2718 affected_file.AbsoluteLocalPath(),
2719 **kwargs)
2720 if parse_error:
2721 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2722 (affected_file.LocalPath(), parse_error)))
2723 return results
2724
2725
Saagar Sanghavifceeaae2020-08-12 16:40:362726def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492727 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472728 import sys
[email protected]760deea2013-12-10 19:33:492729 original_sys_path = sys.path
2730 try:
2731 sys.path = sys.path + [input_api.os_path.join(
2732 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2733 import checkstyle
2734 finally:
2735 # Restore sys.path to what it was before.
2736 sys.path = original_sys_path
2737
2738 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092739 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442740 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492741
2742
Saagar Sanghavifceeaae2020-08-12 16:40:362743def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002744 """Checks to make sure devil is initialized correctly in python scripts."""
2745 script_common_initialize_pattern = input_api.re.compile(
2746 r'script_common\.InitializeEnvironment\(')
2747 devil_env_config_initialize = input_api.re.compile(
2748 r'devil_env\.config\.Initialize\(')
2749
2750 errors = []
2751
2752 sources = lambda affected_file: input_api.FilterSourceFile(
2753 affected_file,
James Cook24a504192020-07-23 00:08:442754 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2755 (r'^build[\\/]android[\\/]devil_chromium\.py',
2756 r'^third_party[\\/].*',)),
2757 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002758
2759 for f in input_api.AffectedSourceFiles(sources):
2760 for line_num, line in f.ChangedContents():
2761 if (script_common_initialize_pattern.search(line) or
2762 devil_env_config_initialize.search(line)):
2763 errors.append("%s:%d" % (f.LocalPath(), line_num))
2764
2765 results = []
2766
2767 if errors:
2768 results.append(output_api.PresubmitError(
2769 'Devil initialization should always be done using '
2770 'devil_chromium.Initialize() in the chromium project, to use better '
2771 'defaults for dependencies (ex. up-to-date version of adb).',
2772 errors))
2773
2774 return results
2775
2776
Sean Kau46e29bc2017-08-28 16:31:162777def _MatchesFile(input_api, patterns, path):
2778 for pattern in patterns:
2779 if input_api.re.search(pattern, path):
2780 return True
2781 return False
2782
2783
Daniel Cheng7052cdf2017-11-21 19:23:292784def _GetOwnersFilesToCheckForIpcOwners(input_api):
2785 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172786
Daniel Cheng7052cdf2017-11-21 19:23:292787 Returns:
2788 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2789 contain to cover IPC-related files with noparent reviewer rules.
2790 """
2791 # Whether or not a file affects IPC is (mostly) determined by a simple list
2792 # of filename patterns.
dchenge07de812016-06-20 19:27:172793 file_patterns = [
palmerb19a0932017-01-24 04:00:312794 # Legacy IPC:
dchenge07de812016-06-20 19:27:172795 '*_messages.cc',
2796 '*_messages*.h',
2797 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312798 # Mojo IPC:
dchenge07de812016-06-20 19:27:172799 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472800 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172801 '*_struct_traits*.*',
2802 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312803 '*.typemap',
2804 # Android native IPC:
2805 '*.aidl',
2806 # Blink uses a different file naming convention:
2807 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472808 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172809 '*StructTraits*.*',
2810 '*TypeConverter*.*',
2811 ]
2812
scottmg7a6ed5ba2016-11-04 18:22:042813 # These third_party directories do not contain IPCs, but contain files
2814 # matching the above patterns, which trigger false positives.
2815 exclude_paths = [
2816 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162817 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232818 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292819 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542820 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162821 # These files are just used to communicate between class loaders running
2822 # in the same process.
2823 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572824 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2825
scottmg7a6ed5ba2016-11-04 18:22:042826 ]
2827
dchenge07de812016-06-20 19:27:172828 # Dictionary mapping an OWNERS file path to Patterns.
2829 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2830 # rules ) to a PatternEntry.
2831 # PatternEntry is a dictionary with two keys:
2832 # - 'files': the files that are matched by this pattern
2833 # - 'rules': the per-file rules needed for this pattern
2834 # For example, if we expect OWNERS file to contain rules for *.mojom and
2835 # *_struct_traits*.*, Patterns might look like this:
2836 # {
2837 # '*.mojom': {
2838 # 'files': ...,
2839 # 'rules': [
2840 # 'per-file *.mojom=set noparent',
2841 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2842 # ],
2843 # },
2844 # '*_struct_traits*.*': {
2845 # 'files': ...,
2846 # 'rules': [
2847 # 'per-file *_struct_traits*.*=set noparent',
2848 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2849 # ],
2850 # },
2851 # }
2852 to_check = {}
2853
Daniel Cheng13ca61a882017-08-25 15:11:252854 def AddPatternToCheck(input_file, pattern):
2855 owners_file = input_api.os_path.join(
2856 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2857 if owners_file not in to_check:
2858 to_check[owners_file] = {}
2859 if pattern not in to_check[owners_file]:
2860 to_check[owners_file][pattern] = {
2861 'files': [],
2862 'rules': [
2863 'per-file %s=set noparent' % pattern,
2864 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2865 ]
2866 }
Vaclav Brozekd5de76a2018-03-17 07:57:502867 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252868
dchenge07de812016-06-20 19:27:172869 # Iterate through the affected files to see what we actually need to check
2870 # for. We should only nag patch authors about per-file rules if a file in that
2871 # directory would match that pattern. If a directory only contains *.mojom
2872 # files and no *_messages*.h files, we should only nag about rules for
2873 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252874 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262875 # Manifest files don't have a strong naming convention. Instead, try to find
2876 # affected .cc and .h files which look like they contain a manifest
2877 # definition.
2878 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2879 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2880 if (manifest_pattern.search(f.LocalPath()) and not
2881 test_manifest_pattern.search(f.LocalPath())):
2882 # We expect all actual service manifest files to contain at least one
2883 # qualified reference to service_manager::Manifest.
2884 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252885 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172886 for pattern in file_patterns:
2887 if input_api.fnmatch.fnmatch(
2888 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042889 skip = False
2890 for exclude in exclude_paths:
2891 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2892 skip = True
2893 break
2894 if skip:
2895 continue
Daniel Cheng13ca61a882017-08-25 15:11:252896 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172897 break
2898
Daniel Cheng7052cdf2017-11-21 19:23:292899 return to_check
2900
2901
Wez17c66962020-04-29 15:26:032902def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2903 """Adds OWNERS files to check for correct Fuchsia security owners."""
2904
2905 file_patterns = [
2906 # Component specifications.
2907 '*.cml', # Component Framework v2.
2908 '*.cmx', # Component Framework v1.
2909
2910 # Fuchsia IDL protocol specifications.
2911 '*.fidl',
2912 ]
2913
Joshua Peraza1ca6d392020-12-08 00:14:092914 # Don't check for owners files for changes in these directories.
2915 exclude_paths = [
2916 'third_party/crashpad/*',
2917 ]
2918
Wez17c66962020-04-29 15:26:032919 def AddPatternToCheck(input_file, pattern):
2920 owners_file = input_api.os_path.join(
2921 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2922 if owners_file not in to_check:
2923 to_check[owners_file] = {}
2924 if pattern not in to_check[owners_file]:
2925 to_check[owners_file][pattern] = {
2926 'files': [],
2927 'rules': [
2928 'per-file %s=set noparent' % pattern,
2929 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2930 ]
2931 }
2932 to_check[owners_file][pattern]['files'].append(input_file)
2933
2934 # Iterate through the affected files to see what we actually need to check
2935 # for. We should only nag patch authors about per-file rules if a file in that
2936 # directory would match that pattern.
2937 for f in input_api.AffectedFiles(include_deletes=False):
Joshua Peraza1ca6d392020-12-08 00:14:092938 skip = False
2939 for exclude in exclude_paths:
2940 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2941 skip = True
2942 if skip:
2943 continue
2944
Wez17c66962020-04-29 15:26:032945 for pattern in file_patterns:
2946 if input_api.fnmatch.fnmatch(
2947 input_api.os_path.basename(f.LocalPath()), pattern):
2948 AddPatternToCheck(f, pattern)
2949 break
2950
2951 return to_check
2952
2953
Saagar Sanghavifceeaae2020-08-12 16:40:362954def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:292955 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2956 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:032957 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:292958
2959 if to_check:
2960 # If there are any OWNERS files to check, there are IPC-related changes in
2961 # this CL. Auto-CC the review list.
2962 output_api.AppendCC('[email protected]')
2963
2964 # Go through the OWNERS files to check, filtering out rules that are already
2965 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172966 for owners_file, patterns in to_check.iteritems():
2967 try:
2968 with file(owners_file) as f:
2969 lines = set(f.read().splitlines())
2970 for entry in patterns.itervalues():
2971 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2972 ]
2973 except IOError:
2974 # No OWNERS file, so all the rules are definitely missing.
2975 continue
2976
2977 # All the remaining lines weren't found in OWNERS files, so emit an error.
2978 errors = []
2979 for owners_file, patterns in to_check.iteritems():
2980 missing_lines = []
2981 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502982 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172983 missing_lines.extend(entry['rules'])
2984 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2985 if missing_lines:
2986 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052987 'Because of the presence of files:\n%s\n\n'
2988 '%s needs the following %d lines added:\n\n%s' %
2989 ('\n'.join(files), owners_file, len(missing_lines),
2990 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172991
2992 results = []
2993 if errors:
vabrf5ce3bf92016-07-11 14:52:412994 if input_api.is_committing:
2995 output = output_api.PresubmitError
2996 else:
2997 output = output_api.PresubmitPromptWarning
2998 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592999 'Found OWNERS files that need to be updated for IPC security ' +
3000 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173001 long_text='\n\n'.join(errors)))
3002
3003 return results
3004
3005
Robert Sesek2c905332020-05-06 23:17:133006def _GetFilesUsingSecurityCriticalFunctions(input_api):
3007 """Checks affected files for changes to security-critical calls. This
3008 function checks the full change diff, to catch both additions/changes
3009 and removals.
3010
3011 Returns a dict keyed by file name, and the value is a set of detected
3012 functions.
3013 """
3014 # Map of function pretty name (displayed in an error) to the pattern to
3015 # match it with.
3016 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373017 'content::GetServiceSandboxType<>()':
3018 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133019 }
3020 _PATTERNS_TO_CHECK = {
3021 k: input_api.re.compile(v)
3022 for k, v in _PATTERNS_TO_CHECK.items()
3023 }
3024
3025 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3026 files_to_functions = {}
3027 for f in input_api.AffectedFiles():
3028 diff = f.GenerateScmDiff()
3029 for line in diff.split('\n'):
3030 # Not using just RightHandSideLines() because removing a
3031 # call to a security-critical function can be just as important
3032 # as adding or changing the arguments.
3033 if line.startswith('-') or (line.startswith('+') and
3034 not line.startswith('++')):
3035 for name, pattern in _PATTERNS_TO_CHECK.items():
3036 if pattern.search(line):
3037 path = f.LocalPath()
3038 if not path in files_to_functions:
3039 files_to_functions[path] = set()
3040 files_to_functions[path].add(name)
3041 return files_to_functions
3042
3043
Saagar Sanghavifceeaae2020-08-12 16:40:363044def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133045 """Checks that changes involving security-critical functions are reviewed
3046 by the security team.
3047 """
3048 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
Edward Lesmes1e9fade2021-02-08 20:31:123049 if not len(files_to_functions):
3050 return []
Robert Sesek2c905332020-05-06 23:17:133051
Edward Lesmes1e9fade2021-02-08 20:31:123052 owner_email, reviewers = (
3053 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3054 input_api,
3055 None,
3056 approval_needed=input_api.is_committing))
Robert Sesek2c905332020-05-06 23:17:133057
Edward Lesmes1e9fade2021-02-08 20:31:123058 # Load the OWNERS file for security changes.
3059 owners_file = 'ipc/SECURITY_OWNERS'
3060 security_owners = input_api.owners_client.ListOwners(owners_file)
3061 has_security_owner = any([owner in reviewers for owner in security_owners])
3062 if has_security_owner:
3063 return []
Robert Sesek2c905332020-05-06 23:17:133064
Edward Lesmes1e9fade2021-02-08 20:31:123065 msg = 'The following files change calls to security-sensive functions\n' \
3066 'that need to be reviewed by {}.\n'.format(owners_file)
3067 for path, names in files_to_functions.items():
3068 msg += ' {}\n'.format(path)
3069 for name in names:
3070 msg += ' {}\n'.format(name)
3071 msg += '\n'
Robert Sesek2c905332020-05-06 23:17:133072
Edward Lesmes1e9fade2021-02-08 20:31:123073 if input_api.is_committing:
3074 output = output_api.PresubmitError
3075 else:
3076 output = output_api.PresubmitNotifyResult
3077 return [output(msg)]
Robert Sesek2c905332020-05-06 23:17:133078
3079
Saagar Sanghavifceeaae2020-08-12 16:40:363080def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263081 """Checks that set noparent is only used together with an OWNERS file in
3082 //build/OWNERS.setnoparent (see also
3083 //docs/code_reviews.md#owners-files-details)
3084 """
3085 errors = []
3086
3087 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3088 allowed_owners_files = set()
3089 with open(allowed_owners_files_file, 'r') as f:
3090 for line in f:
3091 line = line.strip()
3092 if not line or line.startswith('#'):
3093 continue
3094 allowed_owners_files.add(line)
3095
3096 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3097
3098 for f in input_api.AffectedFiles(include_deletes=False):
3099 if not f.LocalPath().endswith('OWNERS'):
3100 continue
3101
3102 found_owners_files = set()
3103 found_set_noparent_lines = dict()
3104
3105 # Parse the OWNERS file.
3106 for lineno, line in enumerate(f.NewContents(), 1):
3107 line = line.strip()
3108 if line.startswith('set noparent'):
3109 found_set_noparent_lines[''] = lineno
3110 if line.startswith('file://'):
3111 if line in allowed_owners_files:
3112 found_owners_files.add('')
3113 if line.startswith('per-file'):
3114 match = per_file_pattern.match(line)
3115 if match:
3116 glob = match.group(1).strip()
3117 directive = match.group(2).strip()
3118 if directive == 'set noparent':
3119 found_set_noparent_lines[glob] = lineno
3120 if directive.startswith('file://'):
3121 if directive in allowed_owners_files:
3122 found_owners_files.add(glob)
Sean McCulloughf5cdfea2021-03-05 00:41:153123
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263124 # Check that every set noparent line has a corresponding file:// line
John Abd-El-Malekdfd1edc2021-02-24 22:22:403125 # listed in build/OWNERS.setnoparent. An exception is made for top level
3126 # directories since src/OWNERS shouldn't review them.
John Abd-El-Malek759fea62021-03-13 03:41:143127 if (f.LocalPath().count('/') != 1 and
3128 (not f.LocalPath() in _EXCLUDED_SET_NO_PARENT_PATHS)):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403129 for set_noparent_line in found_set_noparent_lines:
3130 if set_noparent_line in found_owners_files:
3131 continue
3132 errors.append(' %s:%d' % (f.LocalPath(),
3133 found_set_noparent_lines[set_noparent_line]))
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263134
3135 results = []
3136 if errors:
3137 if input_api.is_committing:
3138 output = output_api.PresubmitError
3139 else:
3140 output = output_api.PresubmitPromptWarning
3141 results.append(output(
3142 'Found the following "set noparent" restrictions in OWNERS files that '
3143 'do not include owners from build/OWNERS.setnoparent:',
3144 long_text='\n\n'.join(errors)))
3145 return results
3146
3147
Saagar Sanghavifceeaae2020-08-12 16:40:363148def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313149 """Checks that added or removed lines in non third party affected
3150 header files do not lead to new useless class or struct forward
3151 declaration.
jbriance9e12f162016-11-25 07:57:503152 """
3153 results = []
3154 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3155 input_api.re.MULTILINE)
3156 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3157 input_api.re.MULTILINE)
3158 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313159 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193160 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493161 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313162 continue
3163
jbriance9e12f162016-11-25 07:57:503164 if not f.LocalPath().endswith('.h'):
3165 continue
3166
3167 contents = input_api.ReadFile(f)
3168 fwd_decls = input_api.re.findall(class_pattern, contents)
3169 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3170
3171 useless_fwd_decls = []
3172 for decl in fwd_decls:
3173 count = sum(1 for _ in input_api.re.finditer(
3174 r'\b%s\b' % input_api.re.escape(decl), contents))
3175 if count == 1:
3176 useless_fwd_decls.append(decl)
3177
3178 if not useless_fwd_decls:
3179 continue
3180
3181 for line in f.GenerateScmDiff().splitlines():
3182 if (line.startswith('-') and not line.startswith('--') or
3183 line.startswith('+') and not line.startswith('++')):
3184 for decl in useless_fwd_decls:
3185 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3186 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243187 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503188 (f.LocalPath(), decl)))
3189 useless_fwd_decls.remove(decl)
3190
3191 return results
3192
Jinsong Fan91ebbbd2019-04-16 14:57:173193def _CheckAndroidDebuggableBuild(input_api, output_api):
3194 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3195 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3196 this is a debuggable build of Android.
3197 """
3198 build_type_check_pattern = input_api.re.compile(
3199 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3200
3201 errors = []
3202
3203 sources = lambda affected_file: input_api.FilterSourceFile(
3204 affected_file,
James Cook24a504192020-07-23 00:08:443205 files_to_skip=(_EXCLUDED_PATHS +
3206 _TEST_CODE_EXCLUDED_PATHS +
3207 input_api.DEFAULT_FILES_TO_SKIP +
3208 (r"^android_webview[\\/]support_library[\\/]"
3209 "boundary_interfaces[\\/]",
3210 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3211 r'^third_party[\\/].*',
3212 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3213 r"webview[\\/]chromium[\\/]License.*",)),
3214 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173215
3216 for f in input_api.AffectedSourceFiles(sources):
3217 for line_num, line in f.ChangedContents():
3218 if build_type_check_pattern.search(line):
3219 errors.append("%s:%d" % (f.LocalPath(), line_num))
3220
3221 results = []
3222
3223 if errors:
3224 results.append(output_api.PresubmitPromptWarning(
3225 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3226 ' Please use BuildInfo.isDebugAndroid() instead.',
3227 errors))
3228
3229 return results
jbriance9e12f162016-11-25 07:57:503230
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493231# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293232def _CheckAndroidToastUsage(input_api, output_api):
3233 """Checks that code uses org.chromium.ui.widget.Toast instead of
3234 android.widget.Toast (Chromium Toast doesn't force hardware
3235 acceleration on low-end devices, saving memory).
3236 """
3237 toast_import_pattern = input_api.re.compile(
3238 r'^import android\.widget\.Toast;$')
3239
3240 errors = []
3241
3242 sources = lambda affected_file: input_api.FilterSourceFile(
3243 affected_file,
James Cook24a504192020-07-23 00:08:443244 files_to_skip=(_EXCLUDED_PATHS +
3245 _TEST_CODE_EXCLUDED_PATHS +
3246 input_api.DEFAULT_FILES_TO_SKIP +
3247 (r'^chromecast[\\/].*',
3248 r'^remoting[\\/].*')),
3249 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293250
3251 for f in input_api.AffectedSourceFiles(sources):
3252 for line_num, line in f.ChangedContents():
3253 if toast_import_pattern.search(line):
3254 errors.append("%s:%d" % (f.LocalPath(), line_num))
3255
3256 results = []
3257
3258 if errors:
3259 results.append(output_api.PresubmitError(
3260 'android.widget.Toast usage is detected. Android toasts use hardware'
3261 ' acceleration, and can be\ncostly on low-end devices. Please use'
3262 ' org.chromium.ui.widget.Toast instead.\n'
3263 'Contact [email protected] if you have any questions.',
3264 errors))
3265
3266 return results
3267
3268
dgnaa68d5e2015-06-10 10:08:223269def _CheckAndroidCrLogUsage(input_api, output_api):
3270 """Checks that new logs using org.chromium.base.Log:
3271 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513272 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223273 """
pkotwicza1dd0b002016-05-16 14:41:043274
torne89540622017-03-24 19:41:303275 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043276 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303277 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043278 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303279 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043280 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3281 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093282 # The customtabs_benchmark is a small app that does not depend on Chromium
3283 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043284 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043285 ]
3286
dgnaa68d5e2015-06-10 10:08:223287 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123288 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3289 class_in_base_pattern = input_api.re.compile(
3290 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3291 has_some_log_import_pattern = input_api.re.compile(
3292 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223293 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553294 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223295 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463296 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553297 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223298
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463299 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443300 sources = lambda x: input_api.FilterSourceFile(x,
3301 files_to_check=[r'.*\.java$'],
3302 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123303
dgnaa68d5e2015-06-10 10:08:223304 tag_decl_errors = []
3305 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123306 tag_errors = []
dgn38736db2015-09-18 19:20:513307 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123308 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223309
3310 for f in input_api.AffectedSourceFiles(sources):
3311 file_content = input_api.ReadFile(f)
3312 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223313 # Per line checks
dgn87d9fb62015-06-12 09:15:123314 if (cr_log_import_pattern.search(file_content) or
3315 (class_in_base_pattern.search(file_content) and
3316 not has_some_log_import_pattern.search(file_content))):
3317 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223318 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553319 if rough_log_decl_pattern.search(line):
3320 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223321
3322 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123323 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223324 if match:
3325 has_modified_logs = True
3326
3327 # Make sure it uses "TAG"
3328 if not match.group('tag') == 'TAG':
3329 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123330 else:
3331 # Report non cr Log function calls in changed lines
3332 for line_num, line in f.ChangedContents():
3333 if log_call_pattern.search(line):
3334 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223335
3336 # Per file checks
3337 if has_modified_logs:
3338 # Make sure the tag is using the "cr" prefix and is not too long
3339 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513340 tag_name = match.group('name') if match else None
3341 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223342 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513343 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223344 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513345 elif '.' in tag_name:
3346 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223347
3348 results = []
3349 if tag_decl_errors:
3350 results.append(output_api.PresubmitPromptWarning(
3351 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513352 '"private static final String TAG = "<package tag>".\n'
3353 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223354 tag_decl_errors))
3355
3356 if tag_length_errors:
3357 results.append(output_api.PresubmitError(
3358 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513359 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223360 tag_length_errors))
3361
3362 if tag_errors:
3363 results.append(output_api.PresubmitPromptWarning(
3364 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3365 tag_errors))
3366
dgn87d9fb62015-06-12 09:15:123367 if util_log_errors:
dgn4401aa52015-04-29 16:26:173368 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123369 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3370 util_log_errors))
3371
dgn38736db2015-09-18 19:20:513372 if tag_with_dot_errors:
3373 results.append(output_api.PresubmitPromptWarning(
3374 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3375 tag_with_dot_errors))
3376
dgn4401aa52015-04-29 16:26:173377 return results
3378
3379
Yoland Yanb92fa522017-08-28 17:37:063380def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3381 """Checks that junit.framework.* is no longer used."""
3382 deprecated_junit_framework_pattern = input_api.re.compile(
3383 r'^import junit\.framework\..*;',
3384 input_api.re.MULTILINE)
3385 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443386 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063387 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133388 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063389 for line_num, line in f.ChangedContents():
3390 if deprecated_junit_framework_pattern.search(line):
3391 errors.append("%s:%d" % (f.LocalPath(), line_num))
3392
3393 results = []
3394 if errors:
3395 results.append(output_api.PresubmitError(
3396 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3397 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3398 ' if you have any question.', errors))
3399 return results
3400
3401
3402def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3403 """Checks that if new Java test classes have inheritance.
3404 Either the new test class is JUnit3 test or it is a JUnit4 test class
3405 with a base class, either case is undesirable.
3406 """
3407 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3408
3409 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443410 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063411 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133412 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063413 if not f.OldContents():
3414 class_declaration_start_flag = False
3415 for line_num, line in f.ChangedContents():
3416 if class_declaration_pattern.search(line):
3417 class_declaration_start_flag = True
3418 if class_declaration_start_flag and ' extends ' in line:
3419 errors.append('%s:%d' % (f.LocalPath(), line_num))
3420 if '{' in line:
3421 class_declaration_start_flag = False
3422
3423 results = []
3424 if errors:
3425 results.append(output_api.PresubmitPromptWarning(
3426 'The newly created files include Test classes that inherits from base'
3427 ' class. Please do not use inheritance in JUnit4 tests or add new'
3428 ' JUnit3 tests. Contact [email protected] if you have any'
3429 ' questions.', errors))
3430 return results
3431
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203432
yolandyan45001472016-12-21 21:12:423433def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3434 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3435 deprecated_annotation_import_pattern = input_api.re.compile(
3436 r'^import android\.test\.suitebuilder\.annotation\..*;',
3437 input_api.re.MULTILINE)
3438 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443439 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423440 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133441 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423442 for line_num, line in f.ChangedContents():
3443 if deprecated_annotation_import_pattern.search(line):
3444 errors.append("%s:%d" % (f.LocalPath(), line_num))
3445
3446 results = []
3447 if errors:
3448 results.append(output_api.PresubmitError(
3449 'Annotations in android.test.suitebuilder.annotation have been'
3450 ' deprecated since API level 24. Please use android.support.test.filters'
3451 ' from //third_party/android_support_test_runner:runner_java instead.'
3452 ' Contact [email protected] if you have any questions.', errors))
3453 return results
3454
3455
agrieve7b6479d82015-10-07 14:24:223456def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3457 """Checks if MDPI assets are placed in a correct directory."""
3458 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3459 ('/res/drawable/' in f.LocalPath() or
3460 '/res/drawable-ldrtl/' in f.LocalPath()))
3461 errors = []
3462 for f in input_api.AffectedFiles(include_deletes=False,
3463 file_filter=file_filter):
3464 errors.append(' %s' % f.LocalPath())
3465
3466 results = []
3467 if errors:
3468 results.append(output_api.PresubmitError(
3469 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3470 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3471 '/res/drawable-ldrtl/.\n'
3472 'Contact [email protected] if you have questions.', errors))
3473 return results
3474
3475
Nate Fischer535972b2017-09-16 01:06:183476def _CheckAndroidWebkitImports(input_api, output_api):
3477 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353478 android.webview.ValueCallback except in the WebView glue layer
3479 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183480 """
3481 valuecallback_import_pattern = input_api.re.compile(
3482 r'^import android\.webkit\.ValueCallback;$')
3483
3484 errors = []
3485
3486 sources = lambda affected_file: input_api.FilterSourceFile(
3487 affected_file,
James Cook24a504192020-07-23 00:08:443488 files_to_skip=(_EXCLUDED_PATHS +
3489 _TEST_CODE_EXCLUDED_PATHS +
3490 input_api.DEFAULT_FILES_TO_SKIP +
3491 (r'^android_webview[\\/]glue[\\/].*',
3492 r'^weblayer[\\/].*',)),
3493 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183494
3495 for f in input_api.AffectedSourceFiles(sources):
3496 for line_num, line in f.ChangedContents():
3497 if valuecallback_import_pattern.search(line):
3498 errors.append("%s:%d" % (f.LocalPath(), line_num))
3499
3500 results = []
3501
3502 if errors:
3503 results.append(output_api.PresubmitError(
3504 'android.webkit.ValueCallback usage is detected outside of the glue'
3505 ' layer. To stay compatible with the support library, android.webkit.*'
3506 ' classes should only be used inside the glue layer and'
3507 ' org.chromium.base.Callback should be used instead.',
3508 errors))
3509
3510 return results
3511
3512
Becky Zhou7c69b50992018-12-10 19:37:573513def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3514 """Checks Android XML styles """
3515 import sys
3516 original_sys_path = sys.path
3517 try:
3518 sys.path = sys.path + [input_api.os_path.join(
3519 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3520 import checkxmlstyle
3521 finally:
3522 # Restore sys.path to what it was before.
3523 sys.path = original_sys_path
3524
3525 if is_check_on_upload:
3526 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3527 else:
3528 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3529
3530
agrievef32bcc72016-04-04 14:57:403531class PydepsChecker(object):
3532 def __init__(self, input_api, pydeps_files):
3533 self._file_cache = {}
3534 self._input_api = input_api
3535 self._pydeps_files = pydeps_files
3536
3537 def _LoadFile(self, path):
3538 """Returns the list of paths within a .pydeps file relative to //."""
3539 if path not in self._file_cache:
3540 with open(path) as f:
3541 self._file_cache[path] = f.read()
3542 return self._file_cache[path]
3543
3544 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3545 """Returns an interable of paths within the .pydep, relativized to //."""
Andrew Grieve5bb4cf702020-10-22 20:21:393546 pydeps_data = self._LoadFile(pydeps_path)
3547 uses_gn_paths = '--gn-paths' in pydeps_data
3548 entries = (l for l in pydeps_data.splitlines() if not l.startswith('#'))
3549 if uses_gn_paths:
3550 # Paths look like: //foo/bar/baz
3551 return (e[2:] for e in entries)
3552 else:
3553 # Paths look like: path/relative/to/file.pydeps
3554 os_path = self._input_api.os_path
3555 pydeps_dir = os_path.dirname(pydeps_path)
3556 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
agrievef32bcc72016-04-04 14:57:403557
3558 def _CreateFilesToPydepsMap(self):
3559 """Returns a map of local_path -> list_of_pydeps."""
3560 ret = {}
3561 for pydep_local_path in self._pydeps_files:
3562 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3563 ret.setdefault(path, []).append(pydep_local_path)
3564 return ret
3565
3566 def ComputeAffectedPydeps(self):
3567 """Returns an iterable of .pydeps files that might need regenerating."""
3568 affected_pydeps = set()
3569 file_to_pydeps_map = None
3570 for f in self._input_api.AffectedFiles(include_deletes=True):
3571 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463572 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3573 # subrepositories. We can't figure out which files change, so re-check
3574 # all files.
3575 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383576 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3577 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403578 return self._pydeps_files
3579 elif local_path.endswith('.pydeps'):
3580 if local_path in self._pydeps_files:
3581 affected_pydeps.add(local_path)
3582 elif local_path.endswith('.py'):
3583 if file_to_pydeps_map is None:
3584 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3585 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3586 return affected_pydeps
3587
3588 def DetermineIfStale(self, pydeps_path):
3589 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413590 import difflib
John Budorick47ca3fe2018-02-10 00:53:103591 import os
3592
agrievef32bcc72016-04-04 14:57:403593 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033594 if old_pydeps_data:
3595 cmd = old_pydeps_data[1][1:].strip()
Andrew Grieve5bb4cf702020-10-22 20:21:393596 if '--output' not in cmd:
3597 cmd += ' --output ' + pydeps_path
Mohamed Heikale217fc852020-07-06 19:44:033598 old_contents = old_pydeps_data[2:]
3599 else:
3600 # A default cmd that should work in most cases (as long as pydeps filename
3601 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3602 # file is empty/new.
3603 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3604 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3605 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103606 env = dict(os.environ)
3607 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403608 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103609 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413610 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033611 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413612 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403613
3614
Tibor Goldschwendt360793f72019-06-25 18:23:493615def _ParseGclientArgs():
3616 args = {}
3617 with open('build/config/gclient_args.gni', 'r') as f:
3618 for line in f:
3619 line = line.strip()
3620 if not line or line.startswith('#'):
3621 continue
3622 attribute, value = line.split('=')
3623 args[attribute.strip()] = value.strip()
3624 return args
3625
3626
Saagar Sanghavifceeaae2020-08-12 16:40:363627def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403628 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403629 # This check is for Python dependency lists (.pydeps files), and involves
3630 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3631 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283632 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003633 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493634 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403635 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403636 results = []
3637 # First, check for new / deleted .pydeps.
3638 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033639 # Check whether we are running the presubmit check for a file in src.
3640 # f.LocalPath is relative to repo (src, or internal repo).
3641 # os_path.exists is relative to src repo.
3642 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3643 # to src and we can conclude that the pydeps is in src.
3644 if input_api.os_path.exists(f.LocalPath()):
3645 if f.LocalPath().endswith('.pydeps'):
3646 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3647 results.append(output_api.PresubmitError(
3648 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3649 'remove %s' % f.LocalPath()))
3650 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3651 results.append(output_api.PresubmitError(
3652 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3653 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403654
3655 if results:
3656 return results
3657
Mohamed Heikal7cd4d8312020-06-16 16:49:403658 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3659 affected_pydeps = set(checker.ComputeAffectedPydeps())
3660 affected_android_pydeps = affected_pydeps.intersection(
3661 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3662 if affected_android_pydeps and not is_android:
3663 results.append(output_api.PresubmitPromptOrNotify(
3664 'You have changed python files that may affect pydeps for android\n'
3665 'specific scripts. However, the relevant presumbit check cannot be\n'
3666 'run because you are not using an Android checkout. To validate that\n'
3667 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3668 'use the android-internal-presubmit optional trybot.\n'
3669 'Possibly stale pydeps files:\n{}'.format(
3670 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403671
Mohamed Heikal7cd4d8312020-06-16 16:49:403672 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3673 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403674 try:
phajdan.jr0d9878552016-11-04 10:49:413675 result = checker.DetermineIfStale(pydep_path)
3676 if result:
3677 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403678 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413679 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3680 'To regenerate, run:\n\n %s' %
3681 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403682 except input_api.subprocess.CalledProcessError as error:
3683 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3684 long_text=error.output)]
3685
3686 return results
3687
3688
Saagar Sanghavifceeaae2020-08-12 16:40:363689def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433690 """Checks to make sure no header files have |Singleton<|."""
3691 def FileFilter(affected_file):
3692 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443693 files_to_skip = (_EXCLUDED_PATHS +
3694 input_api.DEFAULT_FILES_TO_SKIP +
3695 (r"^base[\\/]memory[\\/]singleton\.h$",
3696 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3697 r"quic_singleton_impl\.h$"))
3698 return input_api.FilterSourceFile(affected_file,
3699 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433700
sergeyu34d21222015-09-16 00:11:443701 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433702 files = []
3703 for f in input_api.AffectedSourceFiles(FileFilter):
3704 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3705 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3706 contents = input_api.ReadFile(f)
3707 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243708 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433709 pattern.search(line)):
3710 files.append(f)
3711 break
3712
3713 if files:
yolandyandaabc6d2016-04-18 18:29:393714 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443715 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433716 'Please move them to an appropriate source file so that the ' +
3717 'template gets instantiated in a single compilation unit.',
3718 files) ]
3719 return []
3720
3721
[email protected]fd20b902014-05-09 02:14:533722_DEPRECATED_CSS = [
3723 # Values
3724 ( "-webkit-box", "flex" ),
3725 ( "-webkit-inline-box", "inline-flex" ),
3726 ( "-webkit-flex", "flex" ),
3727 ( "-webkit-inline-flex", "inline-flex" ),
3728 ( "-webkit-min-content", "min-content" ),
3729 ( "-webkit-max-content", "max-content" ),
3730
3731 # Properties
3732 ( "-webkit-background-clip", "background-clip" ),
3733 ( "-webkit-background-origin", "background-origin" ),
3734 ( "-webkit-background-size", "background-size" ),
3735 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443736 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533737
3738 # Functions
3739 ( "-webkit-gradient", "gradient" ),
3740 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3741 ( "-webkit-linear-gradient", "linear-gradient" ),
3742 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3743 ( "-webkit-radial-gradient", "radial-gradient" ),
3744 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3745]
3746
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203747
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493748# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363749def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533750 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253751 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343752 documentation and iOS CSS for dom distiller
3753 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253754 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533755 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493756 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443757 files_to_skip = (_EXCLUDED_PATHS +
3758 _TEST_CODE_EXCLUDED_PATHS +
3759 input_api.DEFAULT_FILES_TO_SKIP +
3760 (r"^chrome/common/extensions/docs",
3761 r"^chrome/docs",
3762 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3763 r"^components/neterror/resources/neterror.css",
3764 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253765 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443766 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533767 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3768 for line_num, line in fpath.ChangedContents():
3769 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023770 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533771 results.append(output_api.PresubmitError(
3772 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3773 (fpath.LocalPath(), line_num, deprecated_value, value)))
3774 return results
3775
mohan.reddyf21db962014-10-16 12:26:473776
Saagar Sanghavifceeaae2020-08-12 16:40:363777def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363778 bad_files = {}
3779 for f in input_api.AffectedFiles(include_deletes=False):
3780 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493781 not f.LocalPath().startswith('third_party/blink') and
3782 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363783 continue
3784
Daniel Bratell65b033262019-04-23 08:17:063785 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363786 continue
3787
Vaclav Brozekd5de76a2018-03-17 07:57:503788 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363789 if "#include" in line and "../" in line]
3790 if not relative_includes:
3791 continue
3792 bad_files[f.LocalPath()] = relative_includes
3793
3794 if not bad_files:
3795 return []
3796
3797 error_descriptions = []
3798 for file_path, bad_lines in bad_files.iteritems():
3799 error_description = file_path
3800 for line in bad_lines:
3801 error_description += '\n ' + line
3802 error_descriptions.append(error_description)
3803
3804 results = []
3805 results.append(output_api.PresubmitError(
3806 'You added one or more relative #include paths (including "../").\n'
3807 'These shouldn\'t be used because they can be used to include headers\n'
3808 'from code that\'s not correctly specified as a dependency in the\n'
3809 'relevant BUILD.gn file(s).',
3810 error_descriptions))
3811
3812 return results
3813
Takeshi Yoshinoe387aa32017-08-02 13:16:133814
Saagar Sanghavifceeaae2020-08-12 16:40:363815def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063816 """Check that nobody tries to include a cc file. It's a relatively
3817 common error which results in duplicate symbols in object
3818 files. This may not always break the build until someone later gets
3819 very confusing linking errors."""
3820 results = []
3821 for f in input_api.AffectedFiles(include_deletes=False):
3822 # We let third_party code do whatever it wants
3823 if (f.LocalPath().startswith('third_party') and
3824 not f.LocalPath().startswith('third_party/blink') and
3825 not f.LocalPath().startswith('third_party\\blink')):
3826 continue
3827
3828 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3829 continue
3830
3831 for _, line in f.ChangedContents():
3832 if line.startswith('#include "'):
3833 included_file = line.split('"')[1]
3834 if _IsCPlusPlusFile(input_api, included_file):
3835 # The most common naming for external files with C++ code,
3836 # apart from standard headers, is to call them foo.inc, but
3837 # Chromium sometimes uses foo-inc.cc so allow that as well.
3838 if not included_file.endswith(('.h', '-inc.cc')):
3839 results.append(output_api.PresubmitError(
3840 'Only header files or .inc files should be included in other\n'
3841 'C++ files. Compiling the contents of a cc file more than once\n'
3842 'will cause duplicate information in the build which may later\n'
3843 'result in strange link_errors.\n' +
3844 f.LocalPath() + ':\n ' +
3845 line))
3846
3847 return results
3848
3849
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203850def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3851 if not isinstance(key, ast.Str):
3852 return 'Key at line %d must be a string literal' % key.lineno
3853 if not isinstance(value, ast.Dict):
3854 return 'Value at line %d must be a dict' % value.lineno
3855 if len(value.keys) != 1:
3856 return 'Dict at line %d must have single entry' % value.lineno
3857 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3858 return (
3859 'Entry at line %d must have a string literal \'filepath\' as key' %
3860 value.lineno)
3861 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133862
Takeshi Yoshinoe387aa32017-08-02 13:16:133863
Sergey Ulanov4af16052018-11-08 02:41:463864def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203865 if not isinstance(key, ast.Str):
3866 return 'Key at line %d must be a string literal' % key.lineno
3867 if not isinstance(value, ast.List):
3868 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463869 for element in value.elts:
3870 if not isinstance(element, ast.Str):
3871 return 'Watchlist elements on line %d is not a string' % key.lineno
3872 if not email_regex.match(element.s):
3873 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3874 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203875 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133876
Takeshi Yoshinoe387aa32017-08-02 13:16:133877
Sergey Ulanov4af16052018-11-08 02:41:463878def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203879 mismatch_template = (
3880 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3881 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133882
Sergey Ulanov4af16052018-11-08 02:41:463883 email_regex = input_api.re.compile(
3884 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3885
3886 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203887 i = 0
3888 last_key = ''
3889 while True:
3890 if i >= len(wd_dict.keys):
3891 if i >= len(w_dict.keys):
3892 return None
3893 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3894 elif i >= len(w_dict.keys):
3895 return (
3896 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133897
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203898 wd_key = wd_dict.keys[i]
3899 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133900
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203901 result = _CheckWatchlistDefinitionsEntrySyntax(
3902 wd_key, wd_dict.values[i], ast)
3903 if result is not None:
3904 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133905
Sergey Ulanov4af16052018-11-08 02:41:463906 result = _CheckWatchlistsEntrySyntax(
3907 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203908 if result is not None:
3909 return 'Bad entry in WATCHLISTS dict: %s' % result
3910
3911 if wd_key.s != w_key.s:
3912 return mismatch_template % (
3913 '%s at line %d' % (wd_key.s, wd_key.lineno),
3914 '%s at line %d' % (w_key.s, w_key.lineno))
3915
3916 if wd_key.s < last_key:
3917 return (
3918 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3919 (wd_key.lineno, w_key.lineno))
3920 last_key = wd_key.s
3921
3922 i = i + 1
3923
3924
Sergey Ulanov4af16052018-11-08 02:41:463925def _CheckWATCHLISTSSyntax(expression, input_api):
3926 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203927 if not isinstance(expression, ast.Expression):
3928 return 'WATCHLISTS file must contain a valid expression'
3929 dictionary = expression.body
3930 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3931 return 'WATCHLISTS file must have single dict with exactly two entries'
3932
3933 first_key = dictionary.keys[0]
3934 first_value = dictionary.values[0]
3935 second_key = dictionary.keys[1]
3936 second_value = dictionary.values[1]
3937
3938 if (not isinstance(first_key, ast.Str) or
3939 first_key.s != 'WATCHLIST_DEFINITIONS' or
3940 not isinstance(first_value, ast.Dict)):
3941 return (
3942 'The first entry of the dict in WATCHLISTS file must be '
3943 'WATCHLIST_DEFINITIONS dict')
3944
3945 if (not isinstance(second_key, ast.Str) or
3946 second_key.s != 'WATCHLISTS' or
3947 not isinstance(second_value, ast.Dict)):
3948 return (
3949 'The second entry of the dict in WATCHLISTS file must be '
3950 'WATCHLISTS dict')
3951
Sergey Ulanov4af16052018-11-08 02:41:463952 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133953
3954
Saagar Sanghavifceeaae2020-08-12 16:40:363955def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:133956 for f in input_api.AffectedFiles(include_deletes=False):
3957 if f.LocalPath() == 'WATCHLISTS':
3958 contents = input_api.ReadFile(f, 'r')
3959
3960 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203961 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133962 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203963 # Get an AST tree for it and scan the tree for detailed style checking.
3964 expression = input_api.ast.parse(
3965 contents, filename='WATCHLISTS', mode='eval')
3966 except ValueError as e:
3967 return [output_api.PresubmitError(
3968 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3969 except SyntaxError as e:
3970 return [output_api.PresubmitError(
3971 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3972 except TypeError as e:
3973 return [output_api.PresubmitError(
3974 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133975
Sergey Ulanov4af16052018-11-08 02:41:463976 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203977 if result is not None:
3978 return [output_api.PresubmitError(result)]
3979 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133980
3981 return []
3982
3983
Andrew Grieve1b290e4a22020-11-24 20:07:013984def CheckGnGlobForward(input_api, output_api):
3985 """Checks that forward_variables_from(invoker, "*") follows best practices.
3986
3987 As documented at //build/docs/writing_gn_templates.md
3988 """
3989 def gn_files(f):
3990 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
3991
3992 problems = []
3993 for f in input_api.AffectedSourceFiles(gn_files):
3994 for line_num, line in f.ChangedContents():
3995 if 'forward_variables_from(invoker, "*")' in line:
3996 problems.append(
3997 'Bare forward_variables_from(invoker, "*") in %s:%d' % (
3998 f.LocalPath(), line_num))
3999
4000 if problems:
4001 return [output_api.PresubmitPromptWarning(
4002 'forward_variables_from("*") without exclusions',
4003 items=sorted(problems),
4004 long_text=('The variables "visibilty" and "test_only" should be '
4005 'explicitly listed in forward_variables_from(). For more '
4006 'details, see:\n'
4007 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4008 'build/docs/writing_gn_templates.md'
4009 '#Using-forward_variables_from'))]
4010 return []
4011
4012
Saagar Sanghavifceeaae2020-08-12 16:40:364013def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194014 """Checks that newly added header files have corresponding GN changes.
4015 Note that this is only a heuristic. To be precise, run script:
4016 build/check_gn_headers.py.
4017 """
4018
4019 def headers(f):
4020 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444021 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194022
4023 new_headers = []
4024 for f in input_api.AffectedSourceFiles(headers):
4025 if f.Action() != 'A':
4026 continue
4027 new_headers.append(f.LocalPath())
4028
4029 def gn_files(f):
James Cook24a504192020-07-23 00:08:444030 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194031
4032 all_gn_changed_contents = ''
4033 for f in input_api.AffectedSourceFiles(gn_files):
4034 for _, line in f.ChangedContents():
4035 all_gn_changed_contents += line
4036
4037 problems = []
4038 for header in new_headers:
4039 basename = input_api.os_path.basename(header)
4040 if basename not in all_gn_changed_contents:
4041 problems.append(header)
4042
4043 if problems:
4044 return [output_api.PresubmitPromptWarning(
4045 'Missing GN changes for new header files', items=sorted(problems),
4046 long_text='Please double check whether newly added header files need '
4047 'corresponding changes in gn or gni files.\nThis checking is only a '
4048 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4049 'Read https://crbug.com/661774 for more info.')]
4050 return []
4051
4052
Saagar Sanghavifceeaae2020-08-12 16:40:364053def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024054 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4055
4056 This assumes we won't intentionally reference one product from the other
4057 product.
4058 """
4059 all_problems = []
4060 test_cases = [{
4061 "filename_postfix": "google_chrome_strings.grd",
4062 "correct_name": "Chrome",
4063 "incorrect_name": "Chromium",
4064 }, {
4065 "filename_postfix": "chromium_strings.grd",
4066 "correct_name": "Chromium",
4067 "incorrect_name": "Chrome",
4068 }]
4069
4070 for test_case in test_cases:
4071 problems = []
4072 filename_filter = lambda x: x.LocalPath().endswith(
4073 test_case["filename_postfix"])
4074
4075 # Check each new line. Can yield false positives in multiline comments, but
4076 # easier than trying to parse the XML because messages can have nested
4077 # children, and associating message elements with affected lines is hard.
4078 for f in input_api.AffectedSourceFiles(filename_filter):
4079 for line_num, line in f.ChangedContents():
4080 if "<message" in line or "<!--" in line or "-->" in line:
4081 continue
4082 if test_case["incorrect_name"] in line:
4083 problems.append(
4084 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4085
4086 if problems:
4087 message = (
4088 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4089 % (test_case["correct_name"], test_case["correct_name"],
4090 test_case["incorrect_name"]))
4091 all_problems.append(
4092 output_api.PresubmitPromptWarning(message, items=problems))
4093
4094 return all_problems
4095
4096
Saagar Sanghavifceeaae2020-08-12 16:40:364097def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364098 """Avoid large files, especially binary files, in the repository since
4099 git doesn't scale well for those. They will be in everyone's repo
4100 clones forever, forever making Chromium slower to clone and work
4101 with."""
4102
4103 # Uploading files to cloud storage is not trivial so we don't want
4104 # to set the limit too low, but the upper limit for "normal" large
4105 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4106 # anything over 20 MB is exceptional.
4107 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4108
4109 too_large_files = []
4110 for f in input_api.AffectedFiles():
4111 # Check both added and modified files (but not deleted files).
4112 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384113 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364114 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4115 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4116
4117 if too_large_files:
4118 message = (
4119 'Do not commit large files to git since git scales badly for those.\n' +
4120 'Instead put the large files in cloud storage and use DEPS to\n' +
4121 'fetch them.\n' + '\n'.join(too_large_files)
4122 )
4123 return [output_api.PresubmitError(
4124 'Too large files found in commit', long_text=message + '\n')]
4125 else:
4126 return []
4127
Max Morozb47503b2019-08-08 21:03:274128
Saagar Sanghavifceeaae2020-08-12 16:40:364129def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274130 """Checks specific for fuzz target sources."""
4131 EXPORTED_SYMBOLS = [
4132 'LLVMFuzzerInitialize',
4133 'LLVMFuzzerCustomMutator',
4134 'LLVMFuzzerCustomCrossOver',
4135 'LLVMFuzzerMutate',
4136 ]
4137
4138 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4139
4140 def FilterFile(affected_file):
4141 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444142 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4143 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274144
4145 return input_api.FilterSourceFile(
4146 affected_file,
James Cook24a504192020-07-23 00:08:444147 files_to_check=[files_to_check],
4148 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274149
4150 files_with_missing_header = []
4151 for f in input_api.AffectedSourceFiles(FilterFile):
4152 contents = input_api.ReadFile(f, 'r')
4153 if REQUIRED_HEADER in contents:
4154 continue
4155
4156 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4157 files_with_missing_header.append(f.LocalPath())
4158
4159 if not files_with_missing_header:
4160 return []
4161
4162 long_text = (
4163 'If you define any of the libFuzzer optional functions (%s), it is '
4164 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4165 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4166 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4167 'to access command line arguments passed to the fuzzer. Instead, prefer '
4168 'static initialization and shared resources as documented in '
4169 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4170 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4171 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4172 )
4173
4174 return [output_api.PresubmitPromptWarning(
4175 message="Missing '%s' in:" % REQUIRED_HEADER,
4176 items=files_with_missing_header,
4177 long_text=long_text)]
4178
4179
Mohamed Heikald048240a2019-11-12 16:57:374180def _CheckNewImagesWarning(input_api, output_api):
4181 """
4182 Warns authors who add images into the repo to make sure their images are
4183 optimized before committing.
4184 """
4185 images_added = False
4186 image_paths = []
4187 errors = []
4188 filter_lambda = lambda x: input_api.FilterSourceFile(
4189 x,
James Cook24a504192020-07-23 00:08:444190 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4191 + input_api.DEFAULT_FILES_TO_SKIP),
4192 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374193 )
4194 for f in input_api.AffectedFiles(
4195 include_deletes=False, file_filter=filter_lambda):
4196 local_path = f.LocalPath().lower()
4197 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4198 images_added = True
4199 image_paths.append(f)
4200 if images_added:
4201 errors.append(output_api.PresubmitPromptWarning(
4202 'It looks like you are trying to commit some images. If these are '
4203 'non-test-only images, please make sure to read and apply the tips in '
4204 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4205 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4206 'FYI only and will not block your CL on the CQ.', image_paths))
4207 return errors
4208
4209
Saagar Sanghavifceeaae2020-08-12 16:40:364210def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574211 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224212 results = []
dgnaa68d5e2015-06-10 10:08:224213 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174214 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224215 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294216 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064217 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4218 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424219 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184220 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574221 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374222 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154223 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574224 return results
4225
Saagar Sanghavifceeaae2020-08-12 16:40:364226def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574227 """Groups commit checks that target android code."""
4228 results = []
4229 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224230 return results
4231
Chris Hall59f8d0c72020-05-01 07:31:194232# TODO(chrishall): could we additionally match on any path owned by
4233# ui/accessibility/OWNERS ?
4234_ACCESSIBILITY_PATHS = (
4235 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4236 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4237 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4238 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4239 r"^content[\\/]browser[\\/]accessibility[\\/]",
4240 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4241 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4242 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4243 r"^ui[\\/]accessibility[\\/]",
4244 r"^ui[\\/]views[\\/]accessibility[\\/]",
4245)
4246
Saagar Sanghavifceeaae2020-08-12 16:40:364247def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194248 """Checks that commits to accessibility code contain an AX-Relnotes field in
4249 their commit message."""
4250 def FileFilter(affected_file):
4251 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444252 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194253
4254 # Only consider changes affecting accessibility paths.
4255 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4256 return []
4257
Akihiro Ota08108e542020-05-20 15:30:534258 # AX-Relnotes can appear in either the description or the footer.
4259 # When searching the description, require 'AX-Relnotes:' to appear at the
4260 # beginning of a line.
4261 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4262 description_has_relnotes = any(ax_regex.match(line)
4263 for line in input_api.change.DescriptionText().lower().splitlines())
4264
4265 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4266 'AX-Relnotes', [])
4267 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194268 return []
4269
4270 # TODO(chrishall): link to Relnotes documentation in message.
4271 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4272 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4273 "user-facing changes"
4274 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4275 "user-facing effects"
4276 "\n if this is confusing or annoying then please contact members "
4277 "of ui/accessibility/OWNERS.")
4278
4279 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224280
seanmccullough4a9356252021-04-08 19:54:094281# string pattern, sequence of strings to show when pattern matches,
4282# error flag. True if match is a presubmit error, otherwise it's a warning.
4283_NON_INCLUSIVE_TERMS = (
4284 (
4285 # Note that \b pattern in python re is pretty particular. In this
4286 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4287 # ...' will not. This may require some tweaking to catch these cases
4288 # without triggering a lot of false positives. Leaving it naive and
4289 # less matchy for now.
4290 r'/\b(?i)((black|white)list|slave)\b', # nocheck
4291 (
4292 'Please don\'t use blacklist, whitelist, ' # nocheck
4293 'or slave in your', # nocheck
4294 'code and make every effort to use other terms. Using "// nocheck"',
4295 '"# nocheck" or "<!-- nocheck -->"',
4296 'at the end of the offending line will bypass this PRESUBMIT error',
4297 'but avoid using this whenever possible. Reach out to',
4298 '[email protected] if you have questions'),
4299 True),)
4300
Saagar Sanghavifceeaae2020-08-12 16:40:364301def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394302 """Checks common to both upload and commit."""
4303 results = []
4304 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384305 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544306 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084307
4308 author = input_api.change.author_email
4309 if author and author not in _KNOWN_ROBOTS:
4310 results.extend(
4311 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4312
[email protected]9f919cc2013-07-31 03:04:044313 results.extend(
4314 input_api.canned_checks.CheckChangeHasNoTabs(
4315 input_api,
4316 output_api,
4317 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434318 results.extend(input_api.RunTests(
4319 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244320
Edward Lesmesce51df52020-08-04 22:10:174321 dirmd_bin = input_api.os_path.join(
4322 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4323 results.extend(input_api.RunTests(
4324 input_api.canned_checks.CheckDirMetadataFormat(
4325 input_api, output_api, dirmd_bin)))
4326 results.extend(
4327 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4328 input_api, output_api))
Edward Lesmes8c62329f2020-12-14 22:46:554329 results.extend(
4330 input_api.canned_checks.CheckNoNewMetadataInOwners(
4331 input_api, output_api))
seanmccullough4a9356252021-04-08 19:54:094332 results.extend(input_api.canned_checks.CheckInclusiveLanguage(
4333 input_api, output_api,
4334 excluded_directories_relative_path = [
4335 'infra',
4336 'inclusive_language_presubmit_exempt_dirs.txt'
4337 ],
4338 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Edward Lesmesce51df52020-08-04 22:10:174339
Vaclav Brozekcdc7defb2018-03-20 09:54:354340 for f in input_api.AffectedFiles():
4341 path, name = input_api.os_path.split(f.LocalPath())
4342 if name == 'PRESUBMIT.py':
4343 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004344 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4345 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074346 # The PRESUBMIT.py file (and the directory containing it) might
4347 # have been affected by being moved or removed, so only try to
4348 # run the tests if they still exist.
4349 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4350 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444351 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394352 return results
[email protected]1f7b4172010-01-28 01:17:344353
[email protected]b337cb5b2011-01-23 21:24:054354
Saagar Sanghavifceeaae2020-08-12 16:40:364355def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494356 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4357 if f.LocalPath().endswith(('.orig', '.rej'))]
4358 if problems:
4359 return [output_api.PresubmitError(
4360 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034361 else:
4362 return []
[email protected]b8079ae4a2012-12-05 19:56:494363
4364
Saagar Sanghavifceeaae2020-08-12 16:40:364365def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214366 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4367 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4368 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074369 include_re = input_api.re.compile(
4370 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4371 extension_re = input_api.re.compile(r'\.[a-z]+$')
4372 errors = []
4373 for f in input_api.AffectedFiles():
4374 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4375 continue
4376 found_line_number = None
4377 found_macro = None
4378 for line_num, line in f.ChangedContents():
4379 match = macro_re.search(line)
4380 if match:
4381 found_line_number = line_num
4382 found_macro = match.group(2)
4383 break
4384 if not found_line_number:
4385 continue
4386
4387 found_include = False
4388 for line in f.NewContents():
4389 if include_re.search(line):
4390 found_include = True
4391 break
4392 if found_include:
4393 continue
4394
4395 if not f.LocalPath().endswith('.h'):
4396 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4397 try:
4398 content = input_api.ReadFile(primary_header_path, 'r')
4399 if include_re.search(content):
4400 continue
4401 except IOError:
4402 pass
4403 errors.append('%s:%d %s macro is used without including build/'
4404 'build_config.h.'
4405 % (f.LocalPath(), found_line_number, found_macro))
4406 if errors:
4407 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4408 return []
4409
4410
[email protected]b00342e7f2013-03-26 16:21:544411def _DidYouMeanOSMacro(bad_macro):
4412 try:
4413 return {'A': 'OS_ANDROID',
4414 'B': 'OS_BSD',
4415 'C': 'OS_CHROMEOS',
4416 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444417 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544418 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444419 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544420 'N': 'OS_NACL',
4421 'O': 'OS_OPENBSD',
4422 'P': 'OS_POSIX',
4423 'S': 'OS_SOLARIS',
4424 'W': 'OS_WIN'}[bad_macro[3].upper()]
4425 except KeyError:
4426 return ''
4427
4428
4429def _CheckForInvalidOSMacrosInFile(input_api, f):
4430 """Check for sensible looking, totally invalid OS macros."""
4431 preprocessor_statement = input_api.re.compile(r'^\s*#')
4432 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4433 results = []
4434 for lnum, line in f.ChangedContents():
4435 if preprocessor_statement.search(line):
4436 for match in os_macro.finditer(line):
4437 if not match.group(1) in _VALID_OS_MACROS:
4438 good = _DidYouMeanOSMacro(match.group(1))
4439 did_you_mean = ' (did you mean %s?)' % good if good else ''
4440 results.append(' %s:%d %s%s' % (f.LocalPath(),
4441 lnum,
4442 match.group(1),
4443 did_you_mean))
4444 return results
4445
4446
Saagar Sanghavifceeaae2020-08-12 16:40:364447def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544448 """Check all affected files for invalid OS macros."""
4449 bad_macros = []
tzik3f295992018-12-04 20:32:234450 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474451 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544452 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4453
4454 if not bad_macros:
4455 return []
4456
4457 return [output_api.PresubmitError(
4458 'Possibly invalid OS macro[s] found. Please fix your code\n'
4459 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4460
lliabraa35bab3932014-10-01 12:16:444461
4462def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4463 """Check all affected files for invalid "if defined" macros."""
4464 ALWAYS_DEFINED_MACROS = (
4465 "TARGET_CPU_PPC",
4466 "TARGET_CPU_PPC64",
4467 "TARGET_CPU_68K",
4468 "TARGET_CPU_X86",
4469 "TARGET_CPU_ARM",
4470 "TARGET_CPU_MIPS",
4471 "TARGET_CPU_SPARC",
4472 "TARGET_CPU_ALPHA",
4473 "TARGET_IPHONE_SIMULATOR",
4474 "TARGET_OS_EMBEDDED",
4475 "TARGET_OS_IPHONE",
4476 "TARGET_OS_MAC",
4477 "TARGET_OS_UNIX",
4478 "TARGET_OS_WIN32",
4479 )
4480 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4481 results = []
4482 for lnum, line in f.ChangedContents():
4483 for match in ifdef_macro.finditer(line):
4484 if match.group(1) in ALWAYS_DEFINED_MACROS:
4485 always_defined = ' %s is always defined. ' % match.group(1)
4486 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4487 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4488 lnum,
4489 always_defined,
4490 did_you_mean))
4491 return results
4492
4493
Saagar Sanghavifceeaae2020-08-12 16:40:364494def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444495 """Check all affected files for invalid "if defined" macros."""
4496 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054497 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444498 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054499 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214500 continue
lliabraa35bab3932014-10-01 12:16:444501 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4502 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4503
4504 if not bad_macros:
4505 return []
4506
4507 return [output_api.PresubmitError(
4508 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4509 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4510 bad_macros)]
4511
4512
Saagar Sanghavifceeaae2020-08-12 16:40:364513def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044514 """Check for same IPC rules described in
4515 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4516 """
4517 base_pattern = r'IPC_ENUM_TRAITS\('
4518 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4519 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4520
4521 problems = []
4522 for f in input_api.AffectedSourceFiles(None):
4523 local_path = f.LocalPath()
4524 if not local_path.endswith('.h'):
4525 continue
4526 for line_number, line in f.ChangedContents():
4527 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4528 problems.append(
4529 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4530
4531 if problems:
4532 return [output_api.PresubmitPromptWarning(
4533 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4534 else:
4535 return []
4536
[email protected]b00342e7f2013-03-26 16:21:544537
Saagar Sanghavifceeaae2020-08-12 16:40:364538def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054539 """Check to make sure no files being submitted have long paths.
4540 This causes issues on Windows.
4541 """
4542 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194543 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054544 local_path = f.LocalPath()
4545 # Windows has a path limit of 260 characters. Limit path length to 200 so
4546 # that we have some extra for the prefix on dev machines and the bots.
4547 if len(local_path) > 200:
4548 problems.append(local_path)
4549
4550 if problems:
4551 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4552 else:
4553 return []
4554
4555
Saagar Sanghavifceeaae2020-08-12 16:40:364556def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144557 """Check that header files have proper guards against multiple inclusion.
4558 If a file should not have such guards (and it probably should) then it
4559 should include the string "no-include-guard-because-multiply-included".
4560 """
Daniel Bratell6a75baef62018-06-04 10:04:454561 def is_chromium_header_file(f):
4562 # We only check header files under the control of the Chromium
4563 # project. That is, those outside third_party apart from
4564 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324565 # We also exclude *_message_generator.h headers as they use
4566 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454567 file_with_path = input_api.os_path.normpath(f.LocalPath())
4568 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324569 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454570 (not file_with_path.startswith('third_party') or
4571 file_with_path.startswith(
4572 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144573
4574 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344575 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144576
4577 errors = []
4578
Daniel Bratell6a75baef62018-06-04 10:04:454579 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144580 guard_name = None
4581 guard_line_number = None
4582 seen_guard_end = False
4583
4584 file_with_path = input_api.os_path.normpath(f.LocalPath())
4585 base_file_name = input_api.os_path.splitext(
4586 input_api.os_path.basename(file_with_path))[0]
4587 upper_base_file_name = base_file_name.upper()
4588
4589 expected_guard = replace_special_with_underscore(
4590 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144591
4592 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574593 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4594 # are too many (1000+) files with slight deviations from the
4595 # coding style. The most important part is that the include guard
4596 # is there, and that it's unique, not the name so this check is
4597 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144598 #
4599 # As code becomes more uniform, this could be made stricter.
4600
4601 guard_name_pattern_list = [
4602 # Anything with the right suffix (maybe with an extra _).
4603 r'\w+_H__?',
4604
Daniel Bratell39b5b062018-05-16 18:09:574605 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144606 r'\w+_h',
4607
4608 # Anything including the uppercase name of the file.
4609 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4610 upper_base_file_name)) + r'\w*',
4611 ]
4612 guard_name_pattern = '|'.join(guard_name_pattern_list)
4613 guard_pattern = input_api.re.compile(
4614 r'#ifndef\s+(' + guard_name_pattern + ')')
4615
4616 for line_number, line in enumerate(f.NewContents()):
4617 if 'no-include-guard-because-multiply-included' in line:
4618 guard_name = 'DUMMY' # To not trigger check outside the loop.
4619 break
4620
4621 if guard_name is None:
4622 match = guard_pattern.match(line)
4623 if match:
4624 guard_name = match.group(1)
4625 guard_line_number = line_number
4626
Daniel Bratell39b5b062018-05-16 18:09:574627 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454628 # don't match the chromium style guide, but new files should
4629 # get it right.
4630 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574631 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144632 errors.append(output_api.PresubmitPromptWarning(
4633 'Header using the wrong include guard name %s' % guard_name,
4634 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574635 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144636 else:
4637 # The line after #ifndef should have a #define of the same name.
4638 if line_number == guard_line_number + 1:
4639 expected_line = '#define %s' % guard_name
4640 if line != expected_line:
4641 errors.append(output_api.PresubmitPromptWarning(
4642 'Missing "%s" for include guard' % expected_line,
4643 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4644 'Expected: %r\nGot: %r' % (expected_line, line)))
4645
4646 if not seen_guard_end and line == '#endif // %s' % guard_name:
4647 seen_guard_end = True
4648 elif seen_guard_end:
4649 if line.strip() != '':
4650 errors.append(output_api.PresubmitPromptWarning(
4651 'Include guard %s not covering the whole file' % (
4652 guard_name), [f.LocalPath()]))
4653 break # Nothing else to check and enough to warn once.
4654
4655 if guard_name is None:
4656 errors.append(output_api.PresubmitPromptWarning(
4657 'Missing include guard %s' % expected_guard,
4658 [f.LocalPath()],
4659 'Missing include guard in %s\n'
4660 'Recommended name: %s\n'
4661 'This check can be disabled by having the string\n'
4662 'no-include-guard-because-multiply-included in the header.' %
4663 (f.LocalPath(), expected_guard)))
4664
4665 return errors
4666
4667
Saagar Sanghavifceeaae2020-08-12 16:40:364668def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234669 """Check source code and known ascii text files for Windows style line
4670 endings.
4671 """
earthdok1b5e0ee2015-03-10 15:19:104672 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234673
4674 file_inclusion_pattern = (
4675 known_text_files,
4676 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4677 )
4678
mostynbb639aca52015-01-07 20:31:234679 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534680 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444681 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534682 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504683 include_file = False
4684 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234685 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504686 include_file = True
4687 if include_file:
4688 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234689
4690 if problems:
4691 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4692 'these files to contain Windows style line endings?\n' +
4693 '\n'.join(problems))]
4694
4695 return []
4696
Jose Magana2b456f22021-03-09 23:26:404697def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
4698 """Check source code for use of Chrome App technologies being
4699 deprecated.
4700 """
4701
4702 def _CheckForDeprecatedTech(input_api, output_api,
4703 detection_list, files_to_check = None, files_to_skip = None):
4704
4705 if (files_to_check or files_to_skip):
4706 source_file_filter = lambda f: input_api.FilterSourceFile(
4707 f, files_to_check=files_to_check,
4708 files_to_skip=files_to_skip)
4709 else:
4710 source_file_filter = None
4711
4712 problems = []
4713
4714 for f in input_api.AffectedSourceFiles(source_file_filter):
4715 if f.Action() == 'D':
4716 continue
4717 for _, line in f.ChangedContents():
4718 if any( detect in line for detect in detection_list ):
4719 problems.append(f.LocalPath())
4720
4721 return problems
4722
4723 # to avoid this presubmit script triggering warnings
4724 files_to_skip = ['PRESUBMIT.py','PRESUBMIT_test.py']
4725
4726 problems =[]
4727
4728 # NMF: any files with extensions .nmf or NMF
4729 _NMF_FILES = r'\.(nmf|NMF)$'
4730 problems += _CheckForDeprecatedTech(input_api, output_api,
4731 detection_list = [''], # any change to the file will trigger warning
4732 files_to_check = [ r'.+%s' % _NMF_FILES ])
4733
4734 # MANIFEST: any manifest.json that in its diff includes "app":
4735 _MANIFEST_FILES = r'(manifest\.json)$'
4736 problems += _CheckForDeprecatedTech(input_api, output_api,
4737 detection_list = ['"app":'],
4738 files_to_check = [ r'.*%s' % _MANIFEST_FILES ])
4739
4740 # NaCl / PNaCl: any file that in its diff contains the strings in the list
4741 problems += _CheckForDeprecatedTech(input_api, output_api,
4742 detection_list = ['config=nacl','enable-nacl','cpu=pnacl', 'nacl_io'],
4743 files_to_skip = files_to_skip + [ r"^native_client_sdk[\\/]"])
4744
4745 # PPAPI: any C/C++ file that in its diff includes a ppappi library
4746 problems += _CheckForDeprecatedTech(input_api, output_api,
4747 detection_list = ['#include "ppapi','#include <ppapi'],
4748 files_to_check = (
4749 r'.+%s' % _HEADER_EXTENSIONS,
4750 r'.+%s' % _IMPLEMENTATION_EXTENSIONS ),
4751 files_to_skip = [r"^ppapi[\\/]"] )
4752
4753 # Chrome Apps: any JS/TS file that references an API in the list below.
4754 # This should include the list of Chrome Apps APIs that are not Chrome
4755 # Extensions APIs as documented in:
4756 # https://developer.chrome.com/docs/apps/migration/
4757 detection_list_chrome_apps = [
4758 'chrome.accessibilityFeatures',
4759 'chrome.alarms',
4760 'chrome.app.runtime',
4761 'chrome.app.window',
4762 'chrome.audio',
4763 'chrome.bluetooth',
4764 'chrome.bluetoothLowEnergy',
4765 'chrome.bluetoothSocket',
4766 'chrome.browser',
4767 'chrome.commands',
4768 'chrome.contextMenus',
4769 'chrome.documentScan',
4770 'chrome.events',
4771 'chrome.extensionTypes',
4772 'chrome.fileSystem',
4773 'chrome.fileSystemProvider',
4774 'chrome.gcm',
4775 'chrome.hid',
4776 'chrome.i18n',
4777 'chrome.identity',
4778 'chrome.idle',
4779 'chrome.instanceID',
4780 'chrome.mdns',
4781 'chrome.mediaGalleries',
4782 'chrome.networking.onc',
4783 'chrome.notifications',
4784 'chrome.permissions',
4785 'chrome.power',
4786 'chrome.printerProvider',
4787 'chrome.runtime',
4788 'chrome.serial',
4789 'chrome.sockets.tcp',
4790 'chrome.sockets.tcpServer',
4791 'chrome.sockets.udp',
4792 'chrome.storage',
4793 'chrome.syncFileSystem',
4794 'chrome.system.cpu',
4795 'chrome.system.display',
4796 'chrome.system.memory',
4797 'chrome.system.network',
4798 'chrome.system.storage',
4799 'chrome.tts',
4800 'chrome.types',
4801 'chrome.usb',
4802 'chrome.virtualKeyboard',
4803 'chrome.vpnProvider',
4804 'chrome.wallpaper'
4805 ]
4806 _JS_FILES = r'\.(js|ts)$'
4807 problems += _CheckForDeprecatedTech(input_api, output_api,
4808 detection_list = detection_list_chrome_apps,
4809 files_to_check = [ r'.+%s' % _JS_FILES ],
4810 files_to_skip = files_to_skip)
4811
4812 if problems:
4813 return [output_api.PresubmitPromptWarning('You are adding/modifying code'
4814 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
4815 ' PNaCl, PPAPI). See this blog post for more details:\n'
4816 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
4817 'and this documentation for options to replace these technologies:\n'
4818 'https://developer.chrome.com/docs/apps/migration/\n'+
4819 '\n'.join(problems))]
4820
4821 return []
4822
mostynbb639aca52015-01-07 20:31:234823
Saagar Sanghavifceeaae2020-08-12 16:40:364824def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134825 """Checks that all source files use SYSLOG properly."""
4826 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364827 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564828 for line_number, line in f.ChangedContents():
4829 if 'SYSLOG' in line:
4830 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4831
pastarmovj89f7ee12016-09-20 14:58:134832 if syslog_files:
4833 return [output_api.PresubmitPromptWarning(
4834 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4835 ' calls.\nFiles to check:\n', items=syslog_files)]
4836 return []
4837
4838
[email protected]1f7b4172010-01-28 01:17:344839def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364840 if input_api.version < [2, 0, 0]:
4841 return [output_api.PresubmitError("Your depot_tools is out of date. "
4842 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4843 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344844 results = []
scottmg39b29952014-12-08 18:31:284845 results.extend(
jam93a6ee792017-02-08 23:59:224846 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544847 return results
[email protected]ca8d1982009-02-19 16:33:124848
4849
[email protected]1bfb8322014-04-23 01:02:414850def GetTryServerMasterForBot(bot):
4851 """Returns the Try Server master for the given bot.
4852
[email protected]0bb112362014-07-26 04:38:324853 It tries to guess the master from the bot name, but may still fail
4854 and return None. There is no longer a default master.
4855 """
4856 # Potentially ambiguous bot names are listed explicitly.
4857 master_map = {
tandriie5587792016-07-14 00:34:504858 'chromium_presubmit': 'master.tryserver.chromium.linux',
4859 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414860 }
[email protected]0bb112362014-07-26 04:38:324861 master = master_map.get(bot)
4862 if not master:
wnwen4fbaab82016-05-25 12:54:364863 if 'android' in bot:
tandriie5587792016-07-14 00:34:504864 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364865 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504866 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324867 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504868 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324869 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504870 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324871 return master
[email protected]1bfb8322014-04-23 01:02:414872
4873
[email protected]ca8d1982009-02-19 16:33:124874def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364875 if input_api.version < [2, 0, 0]:
4876 return [output_api.PresubmitError("Your depot_tools is out of date. "
4877 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4878 "but your version is %d.%d.%d" % tuple(input_api.version))]
4879
[email protected]fe5f57c52009-06-05 14:25:544880 results = []
[email protected]fe5f57c52009-06-05 14:25:544881 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274882 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344883 input_api,
4884 output_api,
[email protected]2fdd1f362013-01-16 03:56:034885 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274886
jam93a6ee792017-02-08 23:59:224887 results.extend(
4888 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544889 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4890 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384891 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4892 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414893 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4894 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544895 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144896
4897
Saagar Sanghavifceeaae2020-08-12 16:40:364898def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264899 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024900 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4901 # footer is set to true.
4902 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264903 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024904 footer.lower()
4905 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264906 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024907
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144908 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264909 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144910 import sys
4911 from io import StringIO
4912
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144913 new_or_added_paths = set(f.LocalPath()
4914 for f in input_api.AffectedFiles()
4915 if (f.Action() == 'A' or f.Action() == 'M'))
4916 removed_paths = set(f.LocalPath()
4917 for f in input_api.AffectedFiles(include_deletes=True)
4918 if f.Action() == 'D')
4919
Andrew Grieve0e8790c2020-09-03 17:27:324920 affected_grds = [
4921 f for f in input_api.AffectedFiles()
4922 if f.LocalPath().endswith(('.grd', '.grdp'))
4923 ]
4924 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164925 if not affected_grds:
4926 return []
4927
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144928 affected_png_paths = [f.AbsoluteLocalPath()
4929 for f in input_api.AffectedFiles()
4930 if (f.LocalPath().endswith('.png'))]
4931
4932 # Check for screenshots. Developers can upload screenshots using
4933 # tools/translation/upload_screenshots.py which finds and uploads
4934 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4935 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4936 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4937 #
4938 # The logic here is as follows:
4939 #
4940 # - If the CL has a .png file under the screenshots directory for a grd
4941 # file, warn the developer. Actual images should never be checked into the
4942 # Chrome repo.
4943 #
4944 # - If the CL contains modified or new messages in grd files and doesn't
4945 # contain the corresponding .sha1 files, warn the developer to add images
4946 # and upload them via tools/translation/upload_screenshots.py.
4947 #
4948 # - If the CL contains modified or new messages in grd files and the
4949 # corresponding .sha1 files, everything looks good.
4950 #
4951 # - If the CL contains removed messages in grd files but the corresponding
4952 # .sha1 files aren't removed, warn the developer to remove them.
4953 unnecessary_screenshots = []
4954 missing_sha1 = []
4955 unnecessary_sha1_files = []
4956
Rainhard Findlingfc31844c52020-05-15 09:58:264957 # This checks verifies that the ICU syntax of messages this CL touched is
4958 # valid, and reports any found syntax errors.
4959 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4960 # without developers being aware of them. Later on, such ICU syntax errors
4961 # break message extraction for translation, hence would block Chromium
4962 # translations until they are fixed.
4963 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144964
4965 def _CheckScreenshotAdded(screenshots_dir, message_id):
4966 sha1_path = input_api.os_path.join(
4967 screenshots_dir, message_id + '.png.sha1')
4968 if sha1_path not in new_or_added_paths:
4969 missing_sha1.append(sha1_path)
4970
4971
4972 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4973 sha1_path = input_api.os_path.join(
4974 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034975 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144976 unnecessary_sha1_files.append(sha1_path)
4977
Rainhard Findlingfc31844c52020-05-15 09:58:264978
4979 def _ValidateIcuSyntax(text, level, signatures):
4980 """Validates ICU syntax of a text string.
4981
4982 Check if text looks similar to ICU and checks for ICU syntax correctness
4983 in this case. Reports various issues with ICU syntax and values of
4984 variants. Supports checking of nested messages. Accumulate information of
4985 each ICU messages found in the text for further checking.
4986
4987 Args:
4988 text: a string to check.
4989 level: a number of current nesting level.
4990 signatures: an accumulator, a list of tuple of (level, variable,
4991 kind, variants).
4992
4993 Returns:
4994 None if a string is not ICU or no issue detected.
4995 A tuple of (message, start index, end index) if an issue detected.
4996 """
4997 valid_types = {
4998 'plural': (frozenset(
4999 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5000 frozenset(['=1', 'other'])),
5001 'selectordinal': (frozenset(
5002 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
5003 frozenset(['one', 'other'])),
5004 'select': (frozenset(), frozenset(['other'])),
5005 }
5006
5007 # Check if the message looks like an attempt to use ICU
5008 # plural. If yes - check if its syntax strictly matches ICU format.
5009 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
5010 if not like:
5011 signatures.append((level, None, None, None))
5012 return
5013
5014 # Check for valid prefix and suffix
5015 m = re.match(
5016 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5017 r'(plural|selectordinal|select),\s*'
5018 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5019 if not m:
5020 return (('This message looks like an ICU plural, '
5021 'but does not follow ICU syntax.'), like.start(), like.end())
5022 starting, variable, kind, variant_pairs = m.groups()
5023 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
5024 if depth:
5025 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5026 len(text))
5027 first = text[0]
5028 ending = text[last_pos:]
5029 if not starting:
5030 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
5031 last_pos)
5032 if not ending or '}' not in ending:
5033 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
5034 last_pos)
5035 elif first != '{':
5036 return (
5037 ('Invalid ICU format. Extra characters at the start of a complex '
5038 'message (go/icu-message-migration): "%s"') %
5039 starting, 0, len(starting))
5040 elif ending != '}':
5041 return (('Invalid ICU format. Extra characters at the end of a complex '
5042 'message (go/icu-message-migration): "%s"')
5043 % ending, last_pos - 1, len(text) - 1)
5044 if kind not in valid_types:
5045 return (('Unknown ICU message type %s. '
5046 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
5047 known, required = valid_types[kind]
5048 defined_variants = set()
5049 for variant, variant_range, value, value_range in variants:
5050 start, end = variant_range
5051 if variant in defined_variants:
5052 return ('Variant "%s" is defined more than once' % variant,
5053 start, end)
5054 elif known and variant not in known:
5055 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5056 start, end)
5057 defined_variants.add(variant)
5058 # Check for nested structure
5059 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5060 if res:
5061 return (res[0], res[1] + value_range[0] + 1,
5062 res[2] + value_range[0] + 1)
5063 missing = required - defined_variants
5064 if missing:
5065 return ('Required variants missing: %s' % ', '.join(missing), 0,
5066 len(text))
5067 signatures.append((level, variable, kind, defined_variants))
5068
5069
5070 def _ParseIcuVariants(text, offset=0):
5071 """Parse variants part of ICU complex message.
5072
5073 Builds a tuple of variant names and values, as well as
5074 their offsets in the input string.
5075
5076 Args:
5077 text: a string to parse
5078 offset: additional offset to add to positions in the text to get correct
5079 position in the complete ICU string.
5080
5081 Returns:
5082 List of tuples, each tuple consist of four fields: variant name,
5083 variant name span (tuple of two integers), variant value, value
5084 span (tuple of two integers).
5085 """
5086 depth, start, end = 0, -1, -1
5087 variants = []
5088 key = None
5089 for idx, char in enumerate(text):
5090 if char == '{':
5091 if not depth:
5092 start = idx
5093 chunk = text[end + 1:start]
5094 key = chunk.strip()
5095 pos = offset + end + 1 + chunk.find(key)
5096 span = (pos, pos + len(key))
5097 depth += 1
5098 elif char == '}':
5099 if not depth:
5100 return variants, depth, offset + idx
5101 depth -= 1
5102 if not depth:
5103 end = idx
5104 variants.append((key, span, text[start:end + 1], (offset + start,
5105 offset + end + 1)))
5106 return variants, depth, offset + end + 1
5107
meacer8c0d3832019-12-26 21:46:165108 try:
5109 old_sys_path = sys.path
5110 sys.path = sys.path + [input_api.os_path.join(
5111 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5112 from helper import grd_helper
5113 finally:
5114 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145115
5116 for f in affected_grds:
5117 file_path = f.LocalPath()
5118 old_id_to_msg_map = {}
5119 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385120 # Note that this code doesn't check if the file has been deleted. This is
5121 # OK because it only uses the old and new file contents and doesn't load
5122 # the file via its path.
5123 # It's also possible that a file's content refers to a renamed or deleted
5124 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5125 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5126 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145127 if file_path.endswith('.grdp'):
5128 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585129 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395130 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145131 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585132 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395133 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145134 else:
meacerff8a9b62019-12-10 19:43:585135 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145136 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585137 old_id_to_msg_map = grd_helper.GetGrdMessages(
5138 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145139 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585140 new_id_to_msg_map = grd_helper.GetGrdMessages(
5141 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145142
Rainhard Findlingd8d04372020-08-13 13:30:095143 grd_name, ext = input_api.os_path.splitext(
5144 input_api.os_path.basename(file_path))
5145 screenshots_dir = input_api.os_path.join(
5146 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5147
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145148 # Compute added, removed and modified message IDs.
5149 old_ids = set(old_id_to_msg_map)
5150 new_ids = set(new_id_to_msg_map)
5151 added_ids = new_ids - old_ids
5152 removed_ids = old_ids - new_ids
5153 modified_ids = set([])
5154 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355155 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095156 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5157 # The message content itself changed. Require an updated screenshot.
5158 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355159 elif old_id_to_msg_map[key].attrs['meaning'] != \
5160 new_id_to_msg_map[key].attrs['meaning']:
5161 # The message meaning changed. Ensure there is a screenshot for it.
5162 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5163 if sha1_path not in new_or_added_paths and not \
5164 input_api.os_path.exists(sha1_path):
5165 # There is neither a previous screenshot nor is a new one added now.
5166 # Require a screenshot.
5167 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145168
Rainhard Findlingfc31844c52020-05-15 09:58:265169 if run_screenshot_check:
5170 # Check the screenshot directory for .png files. Warn if there is any.
5171 for png_path in affected_png_paths:
5172 if png_path.startswith(screenshots_dir):
5173 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145174
Rainhard Findlingfc31844c52020-05-15 09:58:265175 for added_id in added_ids:
5176 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145177
Rainhard Findlingfc31844c52020-05-15 09:58:265178 for modified_id in modified_ids:
5179 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145180
Rainhard Findlingfc31844c52020-05-15 09:58:265181 for removed_id in removed_ids:
5182 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5183
5184 # Check new and changed strings for ICU syntax errors.
5185 for key in added_ids.union(modified_ids):
5186 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5187 err = _ValidateIcuSyntax(msg, 0, [])
5188 if err is not None:
5189 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145190
5191 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265192 if run_screenshot_check:
5193 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005194 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265195 'Do not include actual screenshots in the changelist. Run '
5196 'tools/translate/upload_screenshots.py to upload them instead:',
5197 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145198
Rainhard Findlingfc31844c52020-05-15 09:58:265199 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005200 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265201 'You are adding or modifying UI strings.\n'
5202 'To ensure the best translations, take screenshots of the relevant UI '
5203 '(https://g.co/chrome/translation) and add these files to your '
5204 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145205
Rainhard Findlingfc31844c52020-05-15 09:58:265206 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005207 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265208 'You removed strings associated with these files. Remove:',
5209 sorted(unnecessary_sha1_files)))
5210 else:
5211 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5212 'screenshots check.'))
5213
5214 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075215 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265216 'ICU syntax errors were found in the following strings (problems or '
5217 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145218
5219 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125220
5221
Saagar Sanghavifceeaae2020-08-12 16:40:365222def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125223 repo_root=None,
5224 translation_expectations_path=None,
5225 grd_files=None):
5226 import sys
5227 affected_grds = [f for f in input_api.AffectedFiles()
5228 if (f.LocalPath().endswith('.grd') or
5229 f.LocalPath().endswith('.grdp'))]
5230 if not affected_grds:
5231 return []
5232
5233 try:
5234 old_sys_path = sys.path
5235 sys.path = sys.path + [
5236 input_api.os_path.join(
5237 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5238 from helper import git_helper
5239 from helper import translation_helper
5240 finally:
5241 sys.path = old_sys_path
5242
5243 # Check that translation expectations can be parsed and we can get a list of
5244 # translatable grd files. |repo_root| and |translation_expectations_path| are
5245 # only passed by tests.
5246 if not repo_root:
5247 repo_root = input_api.PresubmitLocalPath()
5248 if not translation_expectations_path:
5249 translation_expectations_path = input_api.os_path.join(
5250 repo_root, 'tools', 'gritsettings',
5251 'translation_expectations.pyl')
5252 if not grd_files:
5253 grd_files = git_helper.list_grds_in_repository(repo_root)
5254
dpapad8e21b472020-10-23 17:15:035255 # Ignore bogus grd files used only for testing
5256 # ui/webui/resoucres/tools/generate_grd.py.
5257 ignore_path = input_api.os_path.join(
5258 'ui', 'webui', 'resources', 'tools', 'tests')
5259 grd_files = filter(lambda p: ignore_path not in p, grd_files)
5260
Mustafa Emre Acer51f2f742020-03-09 19:41:125261 try:
5262 translation_helper.get_translatable_grds(repo_root, grd_files,
5263 translation_expectations_path)
5264 except Exception as e:
5265 return [output_api.PresubmitNotifyResult(
5266 'Failed to get a list of translatable grd files. This happens when:\n'
5267 ' - One of the modified grd or grdp files cannot be parsed or\n'
5268 ' - %s is not updated.\n'
5269 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5270 return []
Ken Rockotc31f4832020-05-29 18:58:515271
5272
Saagar Sanghavifceeaae2020-08-12 16:40:365273def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515274 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095275 changed_mojoms = input_api.AffectedFiles(
5276 include_deletes=True,
5277 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515278 delta = []
5279 for mojom in changed_mojoms:
5280 old_contents = ''.join(mojom.OldContents()) or None
5281 new_contents = ''.join(mojom.NewContents()) or None
5282 delta.append({
5283 'filename': mojom.LocalPath(),
5284 'old': '\n'.join(mojom.OldContents()) or None,
5285 'new': '\n'.join(mojom.NewContents()) or None,
5286 })
5287
5288 process = input_api.subprocess.Popen(
5289 [input_api.python_executable,
5290 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5291 'public', 'tools', 'mojom',
5292 'check_stable_mojom_compatibility.py'),
5293 '--src-root', input_api.PresubmitLocalPath()],
5294 stdin=input_api.subprocess.PIPE,
5295 stdout=input_api.subprocess.PIPE,
5296 stderr=input_api.subprocess.PIPE,
5297 universal_newlines=True)
5298 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5299 if process.returncode:
5300 return [output_api.PresubmitError(
5301 'One or more [Stable] mojom definitions appears to have been changed '
5302 'in a way that is not backward-compatible.',
5303 long_text=error)]
5304 return []
Dominic Battre645d42342020-12-04 16:14:105305
5306def CheckDeprecationOfPreferences(input_api, output_api):
5307 """Removing a preference should come with a deprecation."""
5308
5309 def FilterFile(affected_file):
5310 """Accept only .cc files and the like."""
5311 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5312 files_to_skip = (_EXCLUDED_PATHS +
5313 _TEST_CODE_EXCLUDED_PATHS +
5314 input_api.DEFAULT_FILES_TO_SKIP)
5315 return input_api.FilterSourceFile(
5316 affected_file,
5317 files_to_check=file_inclusion_pattern,
5318 files_to_skip=files_to_skip)
5319
5320 def ModifiedLines(affected_file):
5321 """Returns a list of tuples (line number, line text) of added and removed
5322 lines.
5323
5324 Deleted lines share the same line number as the previous line.
5325
5326 This relies on the scm diff output describing each changed code section
5327 with a line of the form
5328
5329 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5330 """
5331 line_num = 0
5332 modified_lines = []
5333 for line in affected_file.GenerateScmDiff().splitlines():
5334 # Extract <new line num> of the patch fragment (see format above).
5335 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@', line)
5336 if m:
5337 line_num = int(m.groups(1)[0])
5338 continue
5339 if ((line.startswith('+') and not line.startswith('++')) or
5340 (line.startswith('-') and not line.startswith('--'))):
5341 modified_lines.append((line_num, line))
5342
5343 if not line.startswith('-'):
5344 line_num += 1
5345 return modified_lines
5346
5347 def FindLineWith(lines, needle):
5348 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
5349
5350 If 0 or >1 lines contain `needle`, -1 is returned.
5351 """
5352 matching_line_numbers = [
5353 # + 1 for 1-based counting of line numbers.
5354 i + 1 for i, line
5355 in enumerate(lines)
5356 if needle in line]
5357 return matching_line_numbers[0] if len(matching_line_numbers) == 1 else -1
5358
5359 def ModifiedPrefMigration(affected_file):
5360 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5361 # Determine first and last lines of MigrateObsolete.*Pref functions.
5362 new_contents = affected_file.NewContents();
5363 range_1 = (
5364 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5365 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5366 range_2 = (
5367 FindLineWith(new_contents, 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5368 FindLineWith(new_contents, 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5369 if (-1 in range_1 + range_2):
5370 raise Exception(
5371 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.')
5372
5373 # Check whether any of the modified lines are part of the
5374 # MigrateObsolete.*Pref functions.
5375 for line_nr, line in ModifiedLines(affected_file):
5376 if (range_1[0] <= line_nr <= range_1[1] or
5377 range_2[0] <= line_nr <= range_2[1]):
5378 return True
5379 return False
5380
5381 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5382 browser_prefs_file_pattern = input_api.re.compile(
5383 r'chrome/browser/prefs/browser_prefs.cc')
5384
5385 changes = input_api.AffectedFiles(include_deletes=True,
5386 file_filter=FilterFile)
5387 potential_problems = []
5388 for f in changes:
5389 for line in f.GenerateScmDiff().splitlines():
5390 # Check deleted lines for pref registrations.
5391 if (line.startswith('-') and not line.startswith('--') and
5392 register_pref_pattern.search(line)):
5393 potential_problems.append('%s: %s' % (f.LocalPath(), line))
5394
5395 if browser_prefs_file_pattern.search(f.LocalPath()):
5396 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5397 # assume that they knew that they have to deprecate preferences and don't
5398 # warn.
5399 try:
5400 if ModifiedPrefMigration(f):
5401 return []
5402 except Exception as e:
5403 return [output_api.PresubmitError(str(e))]
5404
5405 if potential_problems:
5406 return [output_api.PresubmitPromptWarning(
5407 'Discovered possible removal of preference registrations.\n\n'
5408 'Please make sure to properly deprecate preferences by clearing their\n'
5409 'value for a couple of milestones before finally removing the code.\n'
5410 'Otherwise data may stay in the preferences files forever. See\n'
Gabriel Charetteecb784302021-04-13 14:17:195411 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5412 'chrome/browser/prefs/README.md for examples.\n'
Dominic Battre645d42342020-12-04 16:14:105413 'This may be a false positive warning (e.g. if you move preference\n'
5414 'registrations to a different place).\n',
5415 potential_problems
5416 )]
5417 return []