blob: 0ca5acabb902f04b281cab452d303dd21185474d [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"""
Daniel Chenga44a1bcd2022-03-15 20:00:1510
11from typing import Optional
12from typing import Sequence
13from dataclasses import dataclass
14
Saagar Sanghavifceeaae2020-08-12 16:40:3615PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1216
Dirk Prankee3c9c62d2021-05-18 18:35:5917# This line is 'magic' in that git-cl looks for it to decide whether to
18# use Python3 instead of Python2 when running the code in this file.
19USE_PYTHON3 = True
20
[email protected]379e7dd2010-01-28 17:39:2121_EXCLUDED_PATHS = (
Mila Greene3aa7222021-09-07 16:34:0822 # File needs to write to stdout to emulate a tool it's replacing.
Mila Greend3fc6a42021-09-10 17:38:2323 r"chrome[\\/]updater[\\/]mac[\\/]keystone[\\/]ksadmin.mm",
Ilya Shermane8a7d2d2020-07-25 04:33:4724 # Generated file.
25 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2626 r"client_variations.js"),
Mila Greene3aa7222021-09-07 16:34:0827 r"^native_client_sdksrc[\\/]build_tools[\\/]make_rules.py",
Egor Paskoce145c42018-09-28 19:31:0428 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
29 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
30 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
31 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4932 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0433 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4634 # sqlite is an imported third party dependency.
35 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0436 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5437 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5338 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1239 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0440 r".+[\\/]pnacl_shim\.c$",
41 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0442 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1443 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0444 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5445 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0446 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4047)
[email protected]ca8d1982009-02-19 16:33:1248
John Abd-El-Malek759fea62021-03-13 03:41:1449_EXCLUDED_SET_NO_PARENT_PATHS = (
50 # It's for historical reasons that blink isn't a top level directory, where
51 # it would be allowed to have "set noparent" to avoid top level owners
52 # accidentally +1ing changes.
53 'third_party/blink/OWNERS',
54)
55
wnwenbdc444e2016-05-25 13:44:1556
[email protected]06e6d0ff2012-12-11 01:36:4457# Fragment of a regular expression that matches C++ and Objective-C++
58# implementation files.
59_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
60
wnwenbdc444e2016-05-25 13:44:1561
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1962# Fragment of a regular expression that matches C++ and Objective-C++
63# header files.
64_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
65
66
[email protected]06e6d0ff2012-12-11 01:36:4467# Regular expression that matches code only used for test binaries
68# (best effort).
69_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0470 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4471 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
James Cook1b4dc132021-03-09 22:45:1372 # Test suite files, like:
73 # foo_browsertest.cc
74 # bar_unittest_mac.cc (suffix)
75 # baz_unittests.cc (plural)
76 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(s)?(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1277 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1878 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
Victor Hugo Vianna Silvac22e0202021-06-09 19:46:2179 r'.+sync_service_impl_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0480 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4381 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0482 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4383 # Web test harness.
84 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4785 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0486 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0887 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0488 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4189 # EarlGrey app side code for tests.
90 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1791 # Views Examples code
92 r'ui[\\/]views[\\/]examples[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4193 # Chromium Codelab
94 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4495)
[email protected]ca8d1982009-02-19 16:33:1296
Daniel Bratell609102be2019-03-27 20:53:2197_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1598
[email protected]eea609a2011-11-18 13:10:1299_TEST_ONLY_WARNING = (
100 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:55101 'production code. If you are doing this from inside another method\n'
102 'named as *ForTesting(), then consider exposing things to have tests\n'
103 'make that same call directly.\n'
104 'If that is not possible, you may put a comment on the same line with\n'
105 ' // IN-TEST \n'
106 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
107 'method and can be ignored. Do not do this inside production code.\n'
108 'The android-binary-size trybot will block if the method exists in the\n'
109 'release apk.')
[email protected]eea609a2011-11-18 13:10:12110
111
Daniel Chenga44a1bcd2022-03-15 20:00:15112@dataclass
113class BanRule:
114 # String pattern. If the pattern begins with a slash, the pattern will be
115 # treated as a regular expression instead.
116 pattern: str
117 # Explanation as a sequence of strings. Each string in the sequence will be
118 # printed on its own line.
119 explanation: Sequence[str]
120 # Whether or not to treat this ban as a fatal error. If unspecified, defaults
121 # to true.
122 treat_as_error: Optional[bool] = None
123 # Paths that should be excluded from the ban check. Each string is a regular
124 # expression that will be matched against the path of the file being checked
125 # relative to the root of the source tree.
126 excluded_paths: Optional[Sequence[str]] = None
[email protected]cf9b78f2012-11-14 11:40:28127
Daniel Chenga44a1bcd2022-03-15 20:00:15128
Daniel Cheng917ce542022-03-15 20:46:57129_BANNED_JAVA_IMPORTS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15130 BanRule(
131 'import java.net.URI;',
132 (
133 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
134 ),
135 excluded_paths=(
136 (r'net/android/javatests/src/org/chromium/net/'
137 'AndroidProxySelectorTest\.java'),
138 r'components/cronet/',
139 r'third_party/robolectric/local/',
140 ),
Michael Thiessen44457642020-02-06 00:24:15141 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15142 BanRule(
143 'import android.annotation.TargetApi;',
144 (
145 'Do not use TargetApi, use @androidx.annotation.RequiresApi instead. '
146 'RequiresApi ensures that any calls are guarded by the appropriate '
147 'SDK_INT check. See https://crbug.com/1116486.',
148 ),
149 ),
150 BanRule(
151 'import android.support.test.rule.UiThreadTestRule;',
152 (
153 'Do not use UiThreadTestRule, just use '
154 '@org.chromium.base.test.UiThreadTest on test methods that should run '
155 'on the UI thread. See https://crbug.com/1111893.',
156 ),
157 ),
158 BanRule(
159 'import android.support.test.annotation.UiThreadTest;',
160 ('Do not use android.support.test.annotation.UiThreadTest, use '
161 'org.chromium.base.test.UiThreadTest instead. See '
162 'https://crbug.com/1111893.',
163 ),
164 ),
165 BanRule(
166 'import android.support.test.rule.ActivityTestRule;',
167 (
168 'Do not use ActivityTestRule, use '
169 'org.chromium.base.test.BaseActivityTestRule instead.',
170 ),
171 excluded_paths=(
172 'components/cronet/',
173 ),
174 ),
175)
wnwenbdc444e2016-05-25 13:44:15176
Daniel Cheng917ce542022-03-15 20:46:57177_BANNED_JAVA_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15178 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41179 'StrictMode.allowThreadDiskReads()',
180 (
181 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
182 'directly.',
183 ),
184 False,
185 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15186 BanRule(
Eric Stevensona9a980972017-09-23 00:04:41187 'StrictMode.allowThreadDiskWrites()',
188 (
189 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
190 'directly.',
191 ),
192 False,
193 ),
Daniel Cheng917ce542022-03-15 20:46:57194 BanRule(
Michael Thiessen0f2547e2020-07-27 21:55:36195 '.waitForIdleSync()',
196 (
197 'Do not use waitForIdleSync as it masks underlying issues. There is '
198 'almost always something else you should wait on instead.',
199 ),
200 False,
201 ),
Eric Stevensona9a980972017-09-23 00:04:41202)
203
Daniel Cheng917ce542022-03-15 20:46:57204_BANNED_OBJC_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15205 BanRule(
[email protected]127f18ec2012-06-16 05:05:59206 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20207 (
208 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59209 'prohibited. Please use CrTrackingArea instead.',
210 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
211 ),
212 False,
213 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15214 BanRule(
[email protected]eaae1972014-04-16 04:17:26215 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20216 (
217 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59218 'instead.',
219 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
220 ),
221 False,
222 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15223 BanRule(
[email protected]127f18ec2012-06-16 05:05:59224 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20225 (
226 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59227 'Please use |convertPoint:(point) fromView:nil| instead.',
228 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
229 ),
230 True,
231 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15232 BanRule(
[email protected]127f18ec2012-06-16 05:05:59233 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20234 (
235 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59236 'Please use |convertPoint:(point) toView:nil| instead.',
237 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
238 ),
239 True,
240 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15241 BanRule(
[email protected]127f18ec2012-06-16 05:05:59242 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20243 (
244 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59245 'Please use |convertRect:(point) fromView:nil| instead.',
246 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
247 ),
248 True,
249 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15250 BanRule(
[email protected]127f18ec2012-06-16 05:05:59251 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20252 (
253 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59254 'Please use |convertRect:(point) toView:nil| instead.',
255 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
256 ),
257 True,
258 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15259 BanRule(
[email protected]127f18ec2012-06-16 05:05:59260 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20261 (
262 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59263 'Please use |convertSize:(point) fromView:nil| instead.',
264 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
265 ),
266 True,
267 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15268 BanRule(
[email protected]127f18ec2012-06-16 05:05:59269 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20270 (
271 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59272 'Please use |convertSize:(point) toView:nil| instead.',
273 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
274 ),
275 True,
276 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15277 BanRule(
jif65398702016-10-27 10:19:48278 r"/\s+UTF8String\s*]",
279 (
280 'The use of -[NSString UTF8String] is dangerous as it can return null',
281 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
282 'Please use |SysNSStringToUTF8| instead.',
283 ),
284 True,
285 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15286 BanRule(
Sylvain Defresne4cf1d182017-09-18 14:16:34287 r'__unsafe_unretained',
288 (
289 'The use of __unsafe_unretained is almost certainly wrong, unless',
290 'when interacting with NSFastEnumeration or NSInvocation.',
291 'Please use __weak in files build with ARC, nothing otherwise.',
292 ),
293 False,
294 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15295 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13296 'freeWhenDone:NO',
297 (
298 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
299 'Foundation types is prohibited.',
300 ),
301 True,
302 ),
[email protected]127f18ec2012-06-16 05:05:59303)
304
Sylvain Defresnea8b73d252018-02-28 15:45:54305_BANNED_IOS_OBJC_FUNCTIONS = (
Daniel Chenga44a1bcd2022-03-15 20:00:15306 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54307 r'/\bTEST[(]',
308 (
309 'TEST() macro should not be used in Objective-C++ code as it does not ',
310 'drain the autorelease pool at the end of the test. Use TEST_F() ',
311 'macro instead with a fixture inheriting from PlatformTest (or a ',
312 'typedef).'
313 ),
314 True,
315 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15316 BanRule(
Sylvain Defresnea8b73d252018-02-28 15:45:54317 r'/\btesting::Test\b',
318 (
319 'testing::Test should not be used in Objective-C++ code as it does ',
320 'not drain the autorelease pool at the end of the test. Use ',
321 'PlatformTest instead.'
322 ),
323 True,
324 ),
325)
326
Daniel Cheng917ce542022-03-15 20:46:57327_BANNED_IOS_EGTEST_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15328 BanRule(
Peter K. Lee6c03ccff2019-07-15 14:40:05329 r'/\bEXPECT_OCMOCK_VERIFY\b',
330 (
331 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
332 'it is meant for GTests. Use [mock verify] instead.'
333 ),
334 True,
335 ),
336)
337
Daniel Cheng917ce542022-03-15 20:46:57338_BANNED_CPP_FUNCTIONS : Sequence[BanRule] = (
Daniel Chenga44a1bcd2022-03-15 20:00:15339 BanRule(
Peter Kasting94a56c42019-10-25 21:54:04340 r'/\busing namespace ',
341 (
342 'Using directives ("using namespace x") are banned by the Google Style',
343 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
344 'Explicitly qualify symbols or use using declarations ("using x::foo").',
345 ),
346 True,
347 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
348 ),
Antonio Gomes07300d02019-03-13 20:59:57349 # Make sure that gtest's FRIEND_TEST() macro is not used; the
350 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
351 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
Daniel Chenga44a1bcd2022-03-15 20:00:15352 BanRule(
[email protected]23e6cbc2012-06-16 18:51:20353 'FRIEND_TEST(',
354 (
[email protected]e3c945502012-06-26 20:01:49355 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20356 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
357 ),
358 False,
[email protected]7345da02012-11-27 14:31:49359 (),
[email protected]23e6cbc2012-06-16 18:51:20360 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15361 BanRule(
tomhudsone2c14d552016-05-26 17:07:46362 'setMatrixClip',
363 (
364 'Overriding setMatrixClip() is prohibited; ',
365 'the base function is deprecated. ',
366 ),
367 True,
368 (),
369 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15370 BanRule(
[email protected]52657f62013-05-20 05:30:31371 'SkRefPtr',
372 (
373 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22374 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31375 ),
376 True,
377 (),
378 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15379 BanRule(
[email protected]52657f62013-05-20 05:30:31380 'SkAutoRef',
381 (
382 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22383 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31384 ),
385 True,
386 (),
387 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15388 BanRule(
[email protected]52657f62013-05-20 05:30:31389 'SkAutoTUnref',
390 (
391 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22392 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31393 ),
394 True,
395 (),
396 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15397 BanRule(
[email protected]52657f62013-05-20 05:30:31398 'SkAutoUnref',
399 (
400 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
401 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22402 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31403 ),
404 True,
405 (),
406 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15407 BanRule(
[email protected]d89eec82013-12-03 14:10:59408 r'/HANDLE_EINTR\(.*close',
409 (
410 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
411 'descriptor will be closed, and it is incorrect to retry the close.',
412 'Either call close directly and ignore its return value, or wrap close',
413 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
414 ),
415 True,
416 (),
417 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15418 BanRule(
[email protected]d89eec82013-12-03 14:10:59419 r'/IGNORE_EINTR\((?!.*close)',
420 (
421 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
422 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
423 ),
424 True,
425 (
426 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04427 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
428 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59429 ),
430 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15431 BanRule(
[email protected]ec5b3f02014-04-04 18:43:43432 r'/v8::Extension\(',
433 (
434 'Do not introduce new v8::Extensions into the code base, use',
435 'gin::Wrappable instead. See http://crbug.com/334679',
436 ),
437 True,
[email protected]f55c90ee62014-04-12 00:50:03438 (
Egor Paskoce145c42018-09-28 19:31:04439 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03440 ),
[email protected]ec5b3f02014-04-04 18:43:43441 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15442 BanRule(
jame2d1a952016-04-02 00:27:10443 '#pragma comment(lib,',
444 (
445 'Specify libraries to link with in build files and not in the source.',
446 ),
447 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41448 (
tzik3f295992018-12-04 20:32:23449 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04450 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41451 ),
jame2d1a952016-04-02 00:27:10452 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15453 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02454 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59455 (
456 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
457 ),
458 False,
459 (),
460 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15461 BanRule(
Gabriel Charette7cc6c432018-04-25 20:52:02462 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59463 (
464 'Consider using THREAD_CHECKER macros instead of the class directly.',
465 ),
466 False,
467 (),
468 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15469 BanRule(
Yuri Wiitala2f8de5c2017-07-21 00:11:06470 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
471 (
472 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
473 'deprecated (http://crbug.com/634507). Please avoid converting away',
474 'from the Time types in Chromium code, especially if any math is',
475 'being done on time values. For interfacing with platform/library',
476 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
477 'type converter methods instead. For faking TimeXXX values (for unit',
Peter Kasting53fd6ee2021-10-05 20:40:48478 'testing only), use TimeXXX() + Microseconds(N). For',
Yuri Wiitala2f8de5c2017-07-21 00:11:06479 'other use cases, please contact base/time/OWNERS.',
480 ),
481 False,
482 (),
483 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15484 BanRule(
dbeamb6f4fde2017-06-15 04:03:06485 'CallJavascriptFunctionUnsafe',
486 (
487 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
488 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
489 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
490 ),
491 False,
492 (
Egor Paskoce145c42018-09-28 19:31:04493 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
494 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
495 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06496 ),
497 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15498 BanRule(
dskiba1474c2bfd62017-07-20 02:19:24499 'leveldb::DB::Open',
500 (
501 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
502 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
503 "Chrome's tracing, making their memory usage visible.",
504 ),
505 True,
506 (
507 r'^third_party/leveldatabase/.*\.(cc|h)$',
508 ),
Gabriel Charette0592c3a2017-07-26 12:02:04509 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15510 BanRule(
Chris Mumfordc38afb62017-10-09 17:55:08511 'leveldb::NewMemEnv',
512 (
513 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58514 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
515 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08516 ),
517 True,
518 (
519 r'^third_party/leveldatabase/.*\.(cc|h)$',
520 ),
521 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15522 BanRule(
Gabriel Charetted9839bc2017-07-29 14:17:47523 'RunLoop::QuitCurrent',
524 (
Robert Liao64b7ab22017-08-04 23:03:43525 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
526 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47527 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41528 False,
Gabriel Charetted9839bc2017-07-29 14:17:47529 (),
Gabriel Charettea44975052017-08-21 23:14:04530 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15531 BanRule(
Gabriel Charettea44975052017-08-21 23:14:04532 'base::ScopedMockTimeMessageLoopTaskRunner',
533 (
Gabriel Charette87cc1af2018-04-25 20:52:51534 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11535 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51536 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
537 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
538 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04539 ),
Gabriel Charette87cc1af2018-04-25 20:52:51540 False,
Gabriel Charettea44975052017-08-21 23:14:04541 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57542 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15543 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44544 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57545 (
546 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02547 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57548 ),
549 True,
Danil Chapovalov7bc42a72020-12-09 18:20:16550 # Abseil's benchmarks never linked into chrome.
551 ['third_party/abseil-cpp/.*_benchmark.cc'],
Francois Doray43670e32017-09-27 12:40:38552 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15553 BanRule(
Peter Kasting991618a62019-06-17 22:00:09554 r'/\bstd::stoi\b',
555 (
556 'std::stoi uses exceptions to communicate results. ',
557 'Use base::StringToInt() instead.',
558 ),
559 True,
560 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
561 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15562 BanRule(
Peter Kasting991618a62019-06-17 22:00:09563 r'/\bstd::stol\b',
564 (
565 'std::stol uses exceptions to communicate results. ',
566 'Use base::StringToInt() instead.',
567 ),
568 True,
569 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
570 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15571 BanRule(
Peter Kasting991618a62019-06-17 22:00:09572 r'/\bstd::stoul\b',
573 (
574 'std::stoul uses exceptions to communicate results. ',
575 'Use base::StringToUint() instead.',
576 ),
577 True,
578 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
579 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15580 BanRule(
Peter Kasting991618a62019-06-17 22:00:09581 r'/\bstd::stoll\b',
582 (
583 'std::stoll uses exceptions to communicate results. ',
584 'Use base::StringToInt64() instead.',
585 ),
586 True,
587 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
588 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15589 BanRule(
Peter Kasting991618a62019-06-17 22:00:09590 r'/\bstd::stoull\b',
591 (
592 'std::stoull uses exceptions to communicate results. ',
593 'Use base::StringToUint64() instead.',
594 ),
595 True,
596 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
597 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15598 BanRule(
Peter Kasting991618a62019-06-17 22:00:09599 r'/\bstd::stof\b',
600 (
601 'std::stof uses exceptions to communicate results. ',
602 'For locale-independent values, e.g. reading numbers from disk',
603 'profiles, use base::StringToDouble().',
604 'For user-visible values, parse using ICU.',
605 ),
606 True,
607 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
608 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15609 BanRule(
Peter Kasting991618a62019-06-17 22:00:09610 r'/\bstd::stod\b',
611 (
612 'std::stod uses exceptions to communicate results. ',
613 'For locale-independent values, e.g. reading numbers from disk',
614 'profiles, use base::StringToDouble().',
615 'For user-visible values, parse using ICU.',
616 ),
617 True,
618 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
619 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15620 BanRule(
Peter Kasting991618a62019-06-17 22:00:09621 r'/\bstd::stold\b',
622 (
623 'std::stold uses exceptions to communicate results. ',
624 'For locale-independent values, e.g. reading numbers from disk',
625 'profiles, use base::StringToDouble().',
626 'For user-visible values, parse using ICU.',
627 ),
628 True,
629 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
630 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15631 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45632 r'/\bstd::to_string\b',
633 (
634 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09635 'For locale-independent strings, e.g. writing numbers to disk',
636 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45637 'For user-visible strings, use base::FormatNumber() and',
638 'the related functions in base/i18n/number_formatting.h.',
639 ),
Peter Kasting991618a62019-06-17 22:00:09640 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21641 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45642 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15643 BanRule(
Daniel Bratell69334cc2019-03-26 11:07:45644 r'/\bstd::shared_ptr\b',
645 (
646 'std::shared_ptr should not be used. Use scoped_refptr instead.',
647 ),
648 True,
Ulan Degenbaev947043882021-02-10 14:02:31649 [
650 # Needed for interop with third-party library.
651 '^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
Alex Chau9eb03cdd52020-07-13 21:04:57652 'array_buffer_contents\.(cc|h)',
Ben Kelly39bf6bef2021-10-04 22:54:58653 '^third_party/blink/renderer/bindings/core/v8/' +
654 'v8_wasm_response_extensions.cc',
Wez5f56be52021-05-04 09:30:58655 '^gin/array_buffer\.(cc|h)',
656 '^chrome/services/sharing/nearby/',
Meilin Wang00efc7c2021-05-13 01:12:42657 # gRPC provides some C++ libraries that use std::shared_ptr<>.
658 '^chromeos/services/libassistant/grpc/',
Vigen Issahhanjanfdf9de52021-12-22 21:13:59659 '^chromecast/cast_core/grpc',
660 '^chromecast/cast_core/runtime/browser',
Wez5f56be52021-05-04 09:30:58661 # Fuchsia provides C++ libraries that use std::shared_ptr<>.
Fabrice de Gans3b875422022-04-19 19:40:26662 '^base/fuchsia/filtered_service_directory\.(cc|h)',
663 '^base/fuchsia/service_directory_test_base\.h',
Wez5f56be52021-05-04 09:30:58664 '.*fuchsia.*test\.(cc|h)',
Will Cassella64da6c52022-01-06 18:13:57665 # Needed for clang plugin tests
666 '^tools/clang/plugins/tests/',
Alex Chau9eb03cdd52020-07-13 21:04:57667 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21668 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15669 BanRule(
Peter Kasting991618a62019-06-17 22:00:09670 r'/\bstd::weak_ptr\b',
671 (
672 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
673 ),
674 True,
675 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
676 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15677 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21678 r'/\blong long\b',
679 (
680 'long long is banned. Use stdint.h if you need a 64 bit number.',
681 ),
682 False, # Only a warning since it is already used.
683 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
684 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15685 BanRule(
Daniel Chengc05fcc62022-01-12 16:54:29686 r'\b(absl|std)::any\b',
687 (
Daniel Chenga44a1bcd2022-03-15 20:00:15688 'absl::any / std::any are not safe to use in a component build.',
Daniel Chengc05fcc62022-01-12 16:54:29689 ),
690 True,
691 # Not an error in third party folders, though it probably should be :)
692 [_THIRD_PARTY_EXCEPT_BLINK],
693 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15694 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21695 r'/\bstd::bind\b',
696 (
697 'std::bind is banned because of lifetime risks.',
698 'Use base::BindOnce or base::BindRepeating instead.',
699 ),
700 True,
701 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
702 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15703 BanRule(
Avi Drissman48ee39e2022-02-16 16:31:03704 r'/\bstd::optional\b',
705 (
706 'std::optional is banned. Use absl::optional instead.',
707 ),
708 True,
709 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
710 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15711 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21712 r'/\b#include <chrono>\b',
713 (
714 '<chrono> overlaps with Time APIs in base. Keep using',
715 'base classes.',
716 ),
717 True,
718 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
719 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15720 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21721 r'/\b#include <exception>\b',
722 (
723 'Exceptions are banned and disabled in Chromium.',
724 ),
725 True,
726 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
727 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15728 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21729 r'/\bstd::function\b',
730 (
Colin Blundellea615d422021-05-12 09:35:41731 'std::function is banned. Instead use base::OnceCallback or ',
732 'base::RepeatingCallback, which directly support Chromium\'s weak ',
733 'pointers, ref counting and more.',
Daniel Bratell609102be2019-03-27 20:53:21734 ),
Peter Kasting991618a62019-06-17 22:00:09735 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21736 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
737 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15738 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21739 r'/\b#include <random>\b',
740 (
741 'Do not use any random number engines from <random>. Instead',
742 'use base::RandomBitGenerator.',
743 ),
744 True,
745 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
746 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15747 BanRule(
Tom Andersona95e12042020-09-09 23:08:00748 r'/\b#include <X11/',
749 (
750 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
751 ),
752 True,
753 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
754 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15755 BanRule(
Daniel Bratell609102be2019-03-27 20:53:21756 r'/\bstd::ratio\b',
757 (
758 'std::ratio is banned by the Google Style Guide.',
759 ),
760 True,
761 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45762 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15763 BanRule(
Gabriel Charetted90bcc92021-09-21 00:23:10764 ('base::ThreadRestrictions::ScopedAllowIO'),
Francois Doray43670e32017-09-27 12:40:38765 (
Gabriel Charetted90bcc92021-09-21 00:23:10766 'ScopedAllowIO is deprecated, use ScopedAllowBlocking instead.',
Francois Doray43670e32017-09-27 12:40:38767 ),
Gabriel Charette04b138f2018-08-06 00:03:22768 False,
Francois Doray43670e32017-09-27 12:40:38769 (),
770 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15771 BanRule(
Michael Giuffrida7f93d6922019-04-19 14:39:58772 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19773 (
774 'RunMessageLoop is deprecated, use RunLoop instead.',
775 ),
776 False,
777 (),
778 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15779 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44780 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19781 (
782 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
783 ),
784 False,
785 (),
786 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15787 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44788 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19789 (
790 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
791 "if you're convinced you need this.",
792 ),
793 False,
794 (),
795 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15796 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44797 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19798 (
799 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04800 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19801 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
802 'async events instead of flushing threads.',
803 ),
804 False,
805 (),
806 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15807 BanRule(
Gabriel Charette147335ea2018-03-22 15:59:19808 r'MessageLoopRunner',
809 (
810 'MessageLoopRunner is deprecated, use RunLoop instead.',
811 ),
812 False,
813 (),
814 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15815 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44816 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19817 (
818 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
819 "gab@ if you found a use case where this is the only solution.",
820 ),
821 False,
822 (),
823 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15824 BanRule(
Victor Costane48a2e82019-03-15 22:02:34825 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16826 (
Victor Costane48a2e82019-03-15 22:02:34827 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16828 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
829 ),
830 True,
831 (
832 r'^sql/initialization\.(cc|h)$',
833 r'^third_party/sqlite/.*\.(c|cc|h)$',
834 ),
835 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15836 BanRule(
Dave Tapuska98199b612019-07-10 13:30:44837 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47838 (
839 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
840 'base::RandomShuffle instead.'
841 ),
842 True,
843 (),
844 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15845 BanRule(
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24846 'ios/web/public/test/http_server',
847 (
848 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
849 ),
850 False,
851 (),
852 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15853 BanRule(
Robert Liao764c9492019-01-24 18:46:28854 'GetAddressOf',
855 (
856 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53857 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11858 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53859 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28860 ),
861 True,
862 (),
863 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15864 BanRule(
Ben Lewisa9514602019-04-29 17:53:05865 'SHFileOperation',
866 (
867 'SHFileOperation was deprecated in Windows Vista, and there are less ',
868 'complex functions to achieve the same goals. Use IFileOperation for ',
869 'any esoteric actions instead.'
870 ),
871 True,
872 (),
873 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15874 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51875 'StringFromGUID2',
876 (
877 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24878 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51879 ),
880 True,
881 (
Daniel Chenga44a1bcd2022-03-15 20:00:15882 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51883 ),
884 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15885 BanRule(
Cliff Smolinsky81951642019-04-30 21:39:51886 'StringFromCLSID',
887 (
888 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:24889 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:51890 ),
891 True,
892 (
Daniel Chenga44a1bcd2022-03-15 20:00:15893 r'/base/win/win_util_unittest.cc',
Cliff Smolinsky81951642019-04-30 21:39:51894 ),
895 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15896 BanRule(
Avi Drissman7382afa02019-04-29 23:27:13897 'kCFAllocatorNull',
898 (
899 'The use of kCFAllocatorNull with the NoCopy creation of ',
900 'CoreFoundation types is prohibited.',
901 ),
902 True,
903 (),
904 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15905 BanRule(
Oksana Zhuravlovafd247772019-05-16 16:57:29906 'mojo::ConvertTo',
907 (
908 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
909 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
910 'StringTraits if you would like to convert between custom types and',
911 'the wire format of mojom types.'
912 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:22913 False,
Oksana Zhuravlovafd247772019-05-16 16:57:29914 (
Wezf89dec092019-09-11 19:38:33915 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
916 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:29917 r'^third_party/blink/.*\.(cc|h)$',
918 r'^content/renderer/.*\.(cc|h)$',
919 ),
920 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15921 BanRule(
Oksana Zhuravlovac8222d22019-12-19 19:21:16922 'GetInterfaceProvider',
923 (
924 'InterfaceProvider is deprecated.',
925 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
926 'or Platform::GetBrowserInterfaceBroker.'
927 ),
928 False,
929 (),
930 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15931 BanRule(
Robert Liao1d78df52019-11-11 20:02:01932 'CComPtr',
933 (
934 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
935 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
936 'details.'
937 ),
938 False,
939 (),
940 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15941 BanRule(
Xiaohan Wang72bd2ba2020-02-18 21:38:20942 r'/\b(IFACE|STD)METHOD_?\(',
943 (
944 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
945 'Instead, always use IFACEMETHODIMP in the declaration.'
946 ),
947 False,
948 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
949 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15950 BanRule(
Allen Bauer53b43fb12020-03-12 17:21:47951 'set_owned_by_client',
952 (
953 'set_owned_by_client is deprecated.',
954 'views::View already owns the child views by default. This introduces ',
955 'a competing ownership model which makes the code difficult to reason ',
956 'about. See http://crbug.com/1044687 for more details.'
957 ),
958 False,
959 (),
960 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15961 BanRule(
Peter Boström7ff41522021-07-29 03:43:27962 'RemoveAllChildViewsWithoutDeleting',
963 (
964 'RemoveAllChildViewsWithoutDeleting is deprecated.',
965 'This method is deemed dangerous as, unless raw pointers are re-added,',
966 'calls to this method introduce memory leaks.'
967 ),
968 False,
969 (),
970 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15971 BanRule(
Eric Secklerbe6f48d2020-05-06 18:09:12972 r'/\bTRACE_EVENT_ASYNC_',
973 (
974 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
975 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
976 ),
977 False,
978 (
979 r'^base/trace_event/.*',
980 r'^base/tracing/.*',
981 ),
982 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15983 BanRule(
Aditya Kushwah5a286b72022-02-10 04:54:43984 r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
985 (
986 'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
987 'dumps and may spam crash reports. Consider if the throttled',
988 'variants suffice instead.',
989 ),
990 False,
991 (),
992 ),
Daniel Chenga44a1bcd2022-03-15 20:00:15993 BanRule(
Robert Liao22f66a52021-04-10 00:57:52994 'RoInitialize',
995 (
Robert Liao48018922021-04-16 23:03:02996 'Improper use of [base::win]::RoInitialize() has been implicated in a ',
Robert Liao22f66a52021-04-10 00:57:52997 'few COM initialization leaks. Use base::win::ScopedWinrtInitializer ',
998 'instead. See http://crbug.com/1197722 for more information.'
999 ),
1000 True,
Robert Liao48018922021-04-16 23:03:021001 (
Daniel Chenga44a1bcd2022-03-15 20:00:151002 r'^base[\\/]win[\\/]scoped_winrt_initializer\.cc$',
Robert Liao48018922021-04-16 23:03:021003 ),
Robert Liao22f66a52021-04-10 00:57:521004 ),
[email protected]127f18ec2012-06-16 05:05:591005)
1006
Daniel Cheng92c15e32022-03-16 17:48:221007_BANNED_MOJOM_PATTERNS : Sequence[BanRule] = (
1008 BanRule(
1009 'handle<shared_buffer>',
1010 (
1011 'Please use one of the more specific shared memory types instead:',
1012 ' mojo_base.mojom.ReadOnlySharedMemoryRegion',
1013 ' mojo_base.mojom.WritableSharedMemoryRegion',
1014 ' mojo_base.mojom.UnsafeSharedMemoryRegion',
1015 ),
1016 True,
1017 ),
1018)
1019
mlamouria82272622014-09-16 18:45:041020_IPC_ENUM_TRAITS_DEPRECATED = (
1021 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501022 'See http://www.chromium.org/Home/chromium-security/education/'
1023 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041024
Stephen Martinis97a394142018-06-07 23:06:051025_LONG_PATH_ERROR = (
1026 'Some files included in this CL have file names that are too long (> 200'
1027 ' characters). If committed, these files will cause issues on Windows. See'
1028 ' https://crbug.com/612667 for more details.'
1029)
1030
Shenghua Zhangbfaa38b82017-11-16 21:58:021031_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Scott Violet1dbd37e12021-05-14 16:35:041032 r".*[\\/]AppHooksImpl\.java",
Egor Paskoce145c42018-09-28 19:31:041033 r".*[\\/]BuildHooksAndroidImpl\.java",
1034 r".*[\\/]LicenseContentProvider\.java",
1035 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281036 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021037]
[email protected]127f18ec2012-06-16 05:05:591038
Mohamed Heikald048240a2019-11-12 16:57:371039# List of image extensions that are used as resources in chromium.
1040_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1041
Sean Kau46e29bc2017-08-28 16:31:161042# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401043_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041044 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401045 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041046 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1047 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041048 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431049 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161050]
1051
Andrew Grieveb773bad2020-06-05 18:00:381052# These are not checked on the public chromium-presubmit trybot.
1053# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041054# checkouts.
agrievef32bcc72016-04-04 14:57:401055_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381056 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381057]
1058
1059
1060_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041061 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361062 'base/android/jni_generator/jni_generator.pydeps',
1063 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361064 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041065 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361066 'build/android/gyp/aar.pydeps',
1067 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271068 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361069 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381070 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361071 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021072 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221073 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111074 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361075 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361076 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361077 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111078 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041079 'build/android/gyp/create_app_bundle_apks.pydeps',
1080 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361081 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121082 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091083 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221084 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001085 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361086 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421087 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041088 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361089 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361090 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211091 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361092 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361093 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361094 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581095 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361096 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141097 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261098 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471099 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011100 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041101 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361102 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361103 'build/android/gyp/merge_manifest.pydeps',
1104 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221105 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361106 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461107 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301108 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241109 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361110 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461111 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561112 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361113 'build/android/incremental_install/generate_android_manifest.pydeps',
1114 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041115 'build/android/resource_sizes.pydeps',
1116 'build/android/test_runner.pydeps',
1117 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361118 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361119 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321120 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271121 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1122 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041123 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001124 'components/cronet/tools/generate_javadoc.pydeps',
1125 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381126 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001127 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381128 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041129 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181130 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411131 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1132 'testing/merge_scripts/standard_gtest_merge.pydeps',
1133 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1134 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041135 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421136 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1137 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131138 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501139 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411140 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1141 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061142 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221143 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401144]
1145
wnwenbdc444e2016-05-25 13:44:151146
agrievef32bcc72016-04-04 14:57:401147_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1148
1149
Eric Boren6fd2b932018-01-25 15:05:081150# Bypass the AUTHORS check for these accounts.
1151_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591152 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451153 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591154 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521155 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231156 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471157 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431158 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041159 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271160 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041161 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161162 for s in ('chromium-internal-autoroll',)
1163 ) | set('%[email protected]' % s
1164 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081165
Matt Stark6ef08872021-07-29 01:21:461166_INVALID_GRD_FILE_LINE = [
1167 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1168]
Eric Boren6fd2b932018-01-25 15:05:081169
Daniel Bratell65b033262019-04-23 08:17:061170def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501171 """Returns True if this file contains C++-like code (and not Python,
1172 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061173
Sam Maiera6e76d72022-02-11 21:43:501174 ext = input_api.os_path.splitext(file_path)[1]
1175 # This list is compatible with CppChecker.IsCppFile but we should
1176 # consider adding ".c" to it. If we do that we can use this function
1177 # at more places in the code.
1178 return ext in (
1179 '.h',
1180 '.cc',
1181 '.cpp',
1182 '.m',
1183 '.mm',
1184 )
1185
Daniel Bratell65b033262019-04-23 08:17:061186
1187def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501188 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061189
1190
1191def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501192 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061193
1194
1195def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501196 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061197
Mohamed Heikal5e5b7922020-10-29 18:57:591198
Erik Staabc734cd7a2021-11-23 03:11:521199def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501200 ext = input_api.os_path.splitext(file_path)[1]
1201 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521202
1203
Mohamed Heikal5e5b7922020-10-29 18:57:591204def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501205 """Prevent additions of dependencies from the upstream repo on //clank."""
1206 # clank can depend on clank
1207 if input_api.change.RepositoryRoot().endswith('clank'):
1208 return []
1209 build_file_patterns = [
1210 r'(.+/)?BUILD\.gn',
1211 r'.+\.gni',
1212 ]
1213 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1214 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591215
Sam Maiera6e76d72022-02-11 21:43:501216 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591217
Sam Maiera6e76d72022-02-11 21:43:501218 def FilterFile(affected_file):
1219 return input_api.FilterSourceFile(affected_file,
1220 files_to_check=build_file_patterns,
1221 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591222
Sam Maiera6e76d72022-02-11 21:43:501223 problems = []
1224 for f in input_api.AffectedSourceFiles(FilterFile):
1225 local_path = f.LocalPath()
1226 for line_number, line in f.ChangedContents():
1227 if (bad_pattern.search(line)):
1228 problems.append('%s:%d\n %s' %
1229 (local_path, line_number, line.strip()))
1230 if problems:
1231 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1232 else:
1233 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591234
1235
Saagar Sanghavifceeaae2020-08-12 16:40:361236def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501237 """Attempts to prevent use of functions intended only for testing in
1238 non-testing code. For now this is just a best-effort implementation
1239 that ignores header files and may have some false positives. A
1240 better implementation would probably need a proper C++ parser.
1241 """
1242 # We only scan .cc files and the like, as the declaration of
1243 # for-testing functions in header files are hard to distinguish from
1244 # calls to such functions without a proper C++ parser.
1245 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191246
Sam Maiera6e76d72022-02-11 21:43:501247 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1248 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1249 base_function_pattern)
1250 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1251 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1252 exclusion_pattern = input_api.re.compile(
1253 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1254 (base_function_pattern, base_function_pattern))
1255 # Avoid a false positive in this case, where the method name, the ::, and
1256 # the closing { are all on different lines due to line wrapping.
1257 # HelperClassForTesting::
1258 # HelperClassForTesting(
1259 # args)
1260 # : member(0) {}
1261 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191262
Sam Maiera6e76d72022-02-11 21:43:501263 def FilterFile(affected_file):
1264 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1265 input_api.DEFAULT_FILES_TO_SKIP)
1266 return input_api.FilterSourceFile(
1267 affected_file,
1268 files_to_check=file_inclusion_pattern,
1269 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191270
Sam Maiera6e76d72022-02-11 21:43:501271 problems = []
1272 for f in input_api.AffectedSourceFiles(FilterFile):
1273 local_path = f.LocalPath()
1274 in_method_defn = False
1275 for line_number, line in f.ChangedContents():
1276 if (inclusion_pattern.search(line)
1277 and not comment_pattern.search(line)
1278 and not exclusion_pattern.search(line)
1279 and not allowlist_pattern.search(line)
1280 and not in_method_defn):
1281 problems.append('%s:%d\n %s' %
1282 (local_path, line_number, line.strip()))
1283 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191284
Sam Maiera6e76d72022-02-11 21:43:501285 if problems:
1286 return [
1287 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1288 ]
1289 else:
1290 return []
[email protected]55459852011-08-10 15:17:191291
1292
Saagar Sanghavifceeaae2020-08-12 16:40:361293def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501294 """This is a simplified version of
1295 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1296 """
1297 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1298 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1299 name_pattern = r'ForTest(s|ing)?'
1300 # Describes an occurrence of "ForTest*" inside a // comment.
1301 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1302 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1303 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1304 # Catch calls.
1305 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1306 # Ignore definitions. (Comments are ignored separately.)
1307 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231308
Sam Maiera6e76d72022-02-11 21:43:501309 problems = []
1310 sources = lambda x: input_api.FilterSourceFile(
1311 x,
1312 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1313 DEFAULT_FILES_TO_SKIP),
1314 files_to_check=[r'.*\.java$'])
1315 for f in input_api.AffectedFiles(include_deletes=False,
1316 file_filter=sources):
1317 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231318 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501319 for line_number, line in f.ChangedContents():
1320 if is_inside_javadoc and javadoc_end_re.search(line):
1321 is_inside_javadoc = False
1322 if not is_inside_javadoc and javadoc_start_re.search(line):
1323 is_inside_javadoc = True
1324 if is_inside_javadoc:
1325 continue
1326 if (inclusion_re.search(line) and not comment_re.search(line)
1327 and not annotation_re.search(line)
1328 and not exclusion_re.search(line)):
1329 problems.append('%s:%d\n %s' %
1330 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231331
Sam Maiera6e76d72022-02-11 21:43:501332 if problems:
1333 return [
1334 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1335 ]
1336 else:
1337 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231338
1339
Saagar Sanghavifceeaae2020-08-12 16:40:361340def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501341 """Checks to make sure no .h files include <iostream>."""
1342 files = []
1343 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1344 input_api.re.MULTILINE)
1345 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1346 if not f.LocalPath().endswith('.h'):
1347 continue
1348 contents = input_api.ReadFile(f)
1349 if pattern.search(contents):
1350 files.append(f)
[email protected]10689ca2011-09-02 02:31:541351
Sam Maiera6e76d72022-02-11 21:43:501352 if len(files):
1353 return [
1354 output_api.PresubmitError(
1355 'Do not #include <iostream> in header files, since it inserts static '
1356 'initialization into every file including the header. Instead, '
1357 '#include <ostream>. See http://crbug.com/94794', files)
1358 ]
1359 return []
1360
[email protected]10689ca2011-09-02 02:31:541361
Danil Chapovalov3518f362018-08-11 16:13:431362def _CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501363 """Checks no windows headers with StrCat redefined are included directly."""
1364 files = []
1365 pattern_deny = input_api.re.compile(
1366 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1367 input_api.re.MULTILINE)
1368 pattern_allow = input_api.re.compile(
1369 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
1370 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1371 contents = input_api.ReadFile(f)
1372 if pattern_deny.search(
1373 contents) and not pattern_allow.search(contents):
1374 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431375
Sam Maiera6e76d72022-02-11 21:43:501376 if len(files):
1377 return [
1378 output_api.PresubmitError(
1379 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1380 'directly since they pollute code with StrCat macro. Instead, '
1381 'include matching header from base/win. See http://crbug.com/856536',
1382 files)
1383 ]
1384 return []
Danil Chapovalov3518f362018-08-11 16:13:431385
[email protected]10689ca2011-09-02 02:31:541386
Saagar Sanghavifceeaae2020-08-12 16:40:361387def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501388 """Checks to make sure no source files use UNIT_TEST."""
1389 problems = []
1390 for f in input_api.AffectedFiles():
1391 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1392 continue
[email protected]72df4e782012-06-21 16:28:181393
Sam Maiera6e76d72022-02-11 21:43:501394 for line_num, line in f.ChangedContents():
1395 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1396 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181397
Sam Maiera6e76d72022-02-11 21:43:501398 if not problems:
1399 return []
1400 return [
1401 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1402 '\n'.join(problems))
1403 ]
1404
[email protected]72df4e782012-06-21 16:28:181405
Saagar Sanghavifceeaae2020-08-12 16:40:361406def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501407 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341408
Sam Maiera6e76d72022-02-11 21:43:501409 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1410 instead of DISABLED_. To filter false positives, reports are only generated
1411 if a corresponding MAYBE_ line exists.
1412 """
1413 problems = []
Dominic Battre033531052018-09-24 15:45:341414
Sam Maiera6e76d72022-02-11 21:43:501415 # The following two patterns are looked for in tandem - is a test labeled
1416 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1417 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1418 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341419
Sam Maiera6e76d72022-02-11 21:43:501420 # This is for the case that a test is disabled on all platforms.
1421 full_disable_pattern = input_api.re.compile(
1422 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1423 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341424
Sam Maiera6e76d72022-02-11 21:43:501425 for f in input_api.AffectedFiles(False):
1426 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1427 continue
Dominic Battre033531052018-09-24 15:45:341428
Sam Maiera6e76d72022-02-11 21:43:501429 # Search for MABYE_, DISABLE_ pairs.
1430 disable_lines = {} # Maps of test name to line number.
1431 maybe_lines = {}
1432 for line_num, line in f.ChangedContents():
1433 disable_match = disable_pattern.search(line)
1434 if disable_match:
1435 disable_lines[disable_match.group(1)] = line_num
1436 maybe_match = maybe_pattern.search(line)
1437 if maybe_match:
1438 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341439
Sam Maiera6e76d72022-02-11 21:43:501440 # Search for DISABLE_ occurrences within a TEST() macro.
1441 disable_tests = set(disable_lines.keys())
1442 maybe_tests = set(maybe_lines.keys())
1443 for test in disable_tests.intersection(maybe_tests):
1444 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341445
Sam Maiera6e76d72022-02-11 21:43:501446 contents = input_api.ReadFile(f)
1447 full_disable_match = full_disable_pattern.search(contents)
1448 if full_disable_match:
1449 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341450
Sam Maiera6e76d72022-02-11 21:43:501451 if not problems:
1452 return []
1453 return [
1454 output_api.PresubmitPromptWarning(
1455 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1456 '\n'.join(problems))
1457 ]
1458
Dominic Battre033531052018-09-24 15:45:341459
Nina Satragnof7660532021-09-20 18:03:351460def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501461 """Checks to make sure tests disabled conditionally are not missing a
1462 corresponding MAYBE_ prefix.
1463 """
1464 # Expect at least a lowercase character in the test name. This helps rule out
1465 # false positives with macros wrapping the actual tests name.
1466 define_maybe_pattern = input_api.re.compile(
1467 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191468 # The test_maybe_pattern needs to handle all of these forms. The standard:
1469 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1470 # With a wrapper macro around the test name:
1471 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1472 # And the odd-ball NACL_BROWSER_TEST_f format:
1473 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1474 # The optional E2E_ENABLED-style is handled with (\w*\()?
1475 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1476 # trailing ')'.
1477 test_maybe_pattern = (
1478 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501479 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1480 warnings = []
Nina Satragnof7660532021-09-20 18:03:351481
Sam Maiera6e76d72022-02-11 21:43:501482 # Read the entire files. We can't just read the affected lines, forgetting to
1483 # add MAYBE_ on a change would not show up otherwise.
1484 for f in input_api.AffectedFiles(False):
1485 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1486 continue
1487 contents = input_api.ReadFile(f)
1488 lines = contents.splitlines(True)
1489 current_position = 0
1490 warning_test_names = set()
1491 for line_num, line in enumerate(lines, start=1):
1492 current_position += len(line)
1493 maybe_match = define_maybe_pattern.search(line)
1494 if maybe_match:
1495 test_name = maybe_match.group('test_name')
1496 # Do not warn twice for the same test.
1497 if (test_name in warning_test_names):
1498 continue
1499 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351500
Sam Maiera6e76d72022-02-11 21:43:501501 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1502 # the current position.
1503 test_match = input_api.re.compile(
1504 test_maybe_pattern.format(test_name=test_name),
1505 input_api.re.MULTILINE).search(contents, current_position)
1506 suite_match = input_api.re.compile(
1507 suite_maybe_pattern.format(test_name=test_name),
1508 input_api.re.MULTILINE).search(contents, current_position)
1509 if not test_match and not suite_match:
1510 warnings.append(
1511 output_api.PresubmitPromptWarning(
1512 '%s:%d found MAYBE_ defined without corresponding test %s'
1513 % (f.LocalPath(), line_num, test_name)))
1514 return warnings
1515
[email protected]72df4e782012-06-21 16:28:181516
Saagar Sanghavifceeaae2020-08-12 16:40:361517def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501518 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1519 errors = []
1520 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
1521 input_api.re.MULTILINE)
1522 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1523 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1524 continue
1525 for lnum, line in f.ChangedContents():
1526 if input_api.re.search(pattern, line):
1527 errors.append(
1528 output_api.PresubmitError((
1529 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1530 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1531 (f.LocalPath(), lnum)))
1532 return errors
danakj61c1aa22015-10-26 19:55:521533
1534
Weilun Shia487fad2020-10-28 00:10:341535# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1536# more reliable way. See
1537# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191538
wnwenbdc444e2016-05-25 13:44:151539
Saagar Sanghavifceeaae2020-08-12 16:40:361540def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501541 """Check that FlakyTest annotation is our own instead of the android one"""
1542 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1543 files = []
1544 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1545 if f.LocalPath().endswith('Test.java'):
1546 if pattern.search(input_api.ReadFile(f)):
1547 files.append(f)
1548 if len(files):
1549 return [
1550 output_api.PresubmitError(
1551 'Use org.chromium.base.test.util.FlakyTest instead of '
1552 'android.test.FlakyTest', files)
1553 ]
1554 return []
mcasasb7440c282015-02-04 14:52:191555
wnwenbdc444e2016-05-25 13:44:151556
Saagar Sanghavifceeaae2020-08-12 16:40:361557def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501558 """Make sure .DEPS.git is never modified manually."""
1559 if any(f.LocalPath().endswith('.DEPS.git')
1560 for f in input_api.AffectedFiles()):
1561 return [
1562 output_api.PresubmitError(
1563 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1564 'automated system based on what\'s in DEPS and your changes will be\n'
1565 'overwritten.\n'
1566 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1567 'get-the-code#Rolling_DEPS\n'
1568 'for more information')
1569 ]
1570 return []
[email protected]2a8ac9c2011-10-19 17:20:441571
1572
Saagar Sanghavifceeaae2020-08-12 16:40:361573def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501574 """Checks that DEPS file deps are from allowed_hosts."""
1575 # Run only if DEPS file has been modified to annoy fewer bystanders.
1576 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1577 return []
1578 # Outsource work to gclient verify
1579 try:
1580 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1581 'third_party', 'depot_tools',
1582 'gclient.py')
1583 input_api.subprocess.check_output(
1584 [input_api.python_executable, gclient_path, 'verify'],
1585 stderr=input_api.subprocess.STDOUT)
1586 return []
1587 except input_api.subprocess.CalledProcessError as error:
1588 return [
1589 output_api.PresubmitError(
1590 'DEPS file must have only git dependencies.',
1591 long_text=error.output)
1592 ]
tandriief664692014-09-23 14:51:471593
1594
Mario Sanchez Prada2472cab2019-09-18 10:58:311595def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151596 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501597 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311598
Sam Maiera6e76d72022-02-11 21:43:501599 Returns an string composed of the name of the file, the line number where the
1600 match has been found and the additional text passed as |message| in case the
1601 target type name matches the text inside the line passed as parameter.
1602 """
1603 result = []
Peng Huang9c5949a02020-06-11 19:20:541604
Daniel Chenga44a1bcd2022-03-15 20:00:151605 # Ignore comments about banned types.
1606 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501607 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151608 # A // nocheck comment will bypass this error.
1609 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501610 return result
1611
1612 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151613 if ban_rule.pattern[0:1] == '/':
1614 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501615 if input_api.re.search(regex, line):
1616 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151617 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501618 matched = True
1619
1620 if matched:
1621 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151622 for line in ban_rule.explanation:
1623 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501624
danakjd18e8892020-12-17 17:42:011625 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311626
1627
Saagar Sanghavifceeaae2020-08-12 16:40:361628def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501629 """Make sure that banned functions are not used."""
1630 warnings = []
1631 errors = []
[email protected]127f18ec2012-06-16 05:05:591632
Sam Maiera6e76d72022-02-11 21:43:501633 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151634 if not excluded_paths:
1635 return False
1636
Sam Maiera6e76d72022-02-11 21:43:501637 local_path = affected_file.LocalPath()
1638 for item in excluded_paths:
1639 if input_api.re.match(item, local_path):
1640 return True
1641 return False
wnwenbdc444e2016-05-25 13:44:151642
Sam Maiera6e76d72022-02-11 21:43:501643 def IsIosObjcFile(affected_file):
1644 local_path = affected_file.LocalPath()
1645 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1646 '.h'):
1647 return False
1648 basename = input_api.os_path.basename(local_path)
1649 if 'ios' in basename.split('_'):
1650 return True
1651 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1652 if sep and 'ios' in local_path.split(sep):
1653 return True
1654 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541655
Daniel Chenga44a1bcd2022-03-15 20:00:151656 def CheckForMatch(affected_file, line_num: int, line: str,
1657 ban_rule: BanRule):
1658 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1659 return
1660
Sam Maiera6e76d72022-02-11 21:43:501661 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151662 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501663 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151664 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501665 errors.extend(problems)
1666 else:
1667 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151668
Sam Maiera6e76d72022-02-11 21:43:501669 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1670 for f in input_api.AffectedFiles(file_filter=file_filter):
1671 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151672 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1673 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411674
Sam Maiera6e76d72022-02-11 21:43:501675 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1676 for f in input_api.AffectedFiles(file_filter=file_filter):
1677 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151678 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1679 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591680
Sam Maiera6e76d72022-02-11 21:43:501681 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1682 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151683 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1684 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541685
Sam Maiera6e76d72022-02-11 21:43:501686 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1687 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1688 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151689 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1690 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051691
Sam Maiera6e76d72022-02-11 21:43:501692 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1693 for f in input_api.AffectedFiles(file_filter=file_filter):
1694 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151695 for ban_rule in _BANNED_CPP_FUNCTIONS:
1696 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591697
Daniel Cheng92c15e32022-03-16 17:48:221698 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1699 for f in input_api.AffectedFiles(file_filter=file_filter):
1700 for line_num, line in f.ChangedContents():
1701 for ban_rule in _BANNED_MOJOM_PATTERNS:
1702 CheckForMatch(f, line_num, line, ban_rule)
1703
1704
Sam Maiera6e76d72022-02-11 21:43:501705 result = []
1706 if (warnings):
1707 result.append(
1708 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1709 '\n'.join(warnings)))
1710 if (errors):
1711 result.append(
1712 output_api.PresubmitError('Banned functions were used.\n' +
1713 '\n'.join(errors)))
1714 return result
[email protected]127f18ec2012-06-16 05:05:591715
1716
Michael Thiessen44457642020-02-06 00:24:151717def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501718 """Make sure that banned java imports are not used."""
1719 errors = []
Michael Thiessen44457642020-02-06 00:24:151720
Sam Maiera6e76d72022-02-11 21:43:501721 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1722 for f in input_api.AffectedFiles(file_filter=file_filter):
1723 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151724 for ban_rule in _BANNED_JAVA_IMPORTS:
1725 # Consider merging this into the above function. There is no
1726 # real difference anymore other than helping with a little
1727 # bit of boilerplate text. Doing so means things like
1728 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501729 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151730 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501731 if problems:
1732 errors.extend(problems)
1733 result = []
1734 if (errors):
1735 result.append(
1736 output_api.PresubmitError('Banned imports were used.\n' +
1737 '\n'.join(errors)))
1738 return result
Michael Thiessen44457642020-02-06 00:24:151739
1740
Saagar Sanghavifceeaae2020-08-12 16:40:361741def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501742 """Make sure that banned functions are not used."""
1743 files = []
1744 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1745 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1746 if not f.LocalPath().endswith('.h'):
1747 continue
1748 contents = input_api.ReadFile(f)
1749 if pattern.search(contents):
1750 files.append(f)
[email protected]6c063c62012-07-11 19:11:061751
Sam Maiera6e76d72022-02-11 21:43:501752 if files:
1753 return [
1754 output_api.PresubmitError(
1755 'Do not use #pragma once in header files.\n'
1756 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1757 files)
1758 ]
1759 return []
[email protected]6c063c62012-07-11 19:11:061760
[email protected]127f18ec2012-06-16 05:05:591761
Saagar Sanghavifceeaae2020-08-12 16:40:361762def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501763 """Checks to make sure we don't introduce use of foo ? true : false."""
1764 problems = []
1765 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1766 for f in input_api.AffectedFiles():
1767 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1768 continue
[email protected]e7479052012-09-19 00:26:121769
Sam Maiera6e76d72022-02-11 21:43:501770 for line_num, line in f.ChangedContents():
1771 if pattern.match(line):
1772 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121773
Sam Maiera6e76d72022-02-11 21:43:501774 if not problems:
1775 return []
1776 return [
1777 output_api.PresubmitPromptWarning(
1778 'Please consider avoiding the "? true : false" pattern if possible.\n'
1779 + '\n'.join(problems))
1780 ]
[email protected]e7479052012-09-19 00:26:121781
1782
Saagar Sanghavifceeaae2020-08-12 16:40:361783def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501784 """Runs checkdeps on #include and import statements added in this
1785 change. Breaking - rules is an error, breaking ! rules is a
1786 warning.
1787 """
1788 # Return early if no relevant file types were modified.
1789 for f in input_api.AffectedFiles():
1790 path = f.LocalPath()
1791 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1792 or _IsJavaFile(input_api, path)):
1793 break
[email protected]55f9f382012-07-31 11:02:181794 else:
Sam Maiera6e76d72022-02-11 21:43:501795 return []
rhalavati08acd232017-04-03 07:23:281796
Sam Maiera6e76d72022-02-11 21:43:501797 import sys
1798 # We need to wait until we have an input_api object and use this
1799 # roundabout construct to import checkdeps because this file is
1800 # eval-ed and thus doesn't have __file__.
1801 original_sys_path = sys.path
1802 try:
1803 sys.path = sys.path + [
1804 input_api.os_path.join(input_api.PresubmitLocalPath(),
1805 'buildtools', 'checkdeps')
1806 ]
1807 import checkdeps
1808 from rules import Rule
1809 finally:
1810 # Restore sys.path to what it was before.
1811 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181812
Sam Maiera6e76d72022-02-11 21:43:501813 added_includes = []
1814 added_imports = []
1815 added_java_imports = []
1816 for f in input_api.AffectedFiles():
1817 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1818 changed_lines = [line for _, line in f.ChangedContents()]
1819 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1820 elif _IsProtoFile(input_api, f.LocalPath()):
1821 changed_lines = [line for _, line in f.ChangedContents()]
1822 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1823 elif _IsJavaFile(input_api, f.LocalPath()):
1824 changed_lines = [line for _, line in f.ChangedContents()]
1825 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241826
Sam Maiera6e76d72022-02-11 21:43:501827 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1828
1829 error_descriptions = []
1830 warning_descriptions = []
1831 error_subjects = set()
1832 warning_subjects = set()
1833
1834 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1835 added_includes):
1836 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1837 description_with_path = '%s\n %s' % (path, rule_description)
1838 if rule_type == Rule.DISALLOW:
1839 error_descriptions.append(description_with_path)
1840 error_subjects.add("#includes")
1841 else:
1842 warning_descriptions.append(description_with_path)
1843 warning_subjects.add("#includes")
1844
1845 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1846 added_imports):
1847 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1848 description_with_path = '%s\n %s' % (path, rule_description)
1849 if rule_type == Rule.DISALLOW:
1850 error_descriptions.append(description_with_path)
1851 error_subjects.add("imports")
1852 else:
1853 warning_descriptions.append(description_with_path)
1854 warning_subjects.add("imports")
1855
1856 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1857 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1858 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1859 description_with_path = '%s\n %s' % (path, rule_description)
1860 if rule_type == Rule.DISALLOW:
1861 error_descriptions.append(description_with_path)
1862 error_subjects.add("imports")
1863 else:
1864 warning_descriptions.append(description_with_path)
1865 warning_subjects.add("imports")
1866
1867 results = []
1868 if error_descriptions:
1869 results.append(
1870 output_api.PresubmitError(
1871 'You added one or more %s that violate checkdeps rules.' %
1872 " and ".join(error_subjects), error_descriptions))
1873 if warning_descriptions:
1874 results.append(
1875 output_api.PresubmitPromptOrNotify(
1876 'You added one or more %s of files that are temporarily\n'
1877 'allowed but being removed. Can you avoid introducing the\n'
1878 '%s? See relevant DEPS file(s) for details and contacts.' %
1879 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1880 warning_descriptions))
1881 return results
[email protected]55f9f382012-07-31 11:02:181882
1883
Saagar Sanghavifceeaae2020-08-12 16:40:361884def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501885 """Check that all files have their permissions properly set."""
1886 if input_api.platform == 'win32':
1887 return []
1888 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1889 'tools', 'checkperms',
1890 'checkperms.py')
1891 args = [
1892 input_api.python_executable, checkperms_tool, '--root',
1893 input_api.change.RepositoryRoot()
1894 ]
1895 with input_api.CreateTemporaryFile() as file_list:
1896 for f in input_api.AffectedFiles():
1897 # checkperms.py file/directory arguments must be relative to the
1898 # repository.
1899 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1900 file_list.close()
1901 args += ['--file-list', file_list.name]
1902 try:
1903 input_api.subprocess.check_output(args)
1904 return []
1905 except input_api.subprocess.CalledProcessError as error:
1906 return [
1907 output_api.PresubmitError('checkperms.py failed:',
1908 long_text=error.output.decode(
1909 'utf-8', 'ignore'))
1910 ]
[email protected]fbcafe5a2012-08-08 15:31:221911
1912
Saagar Sanghavifceeaae2020-08-12 16:40:361913def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501914 """Makes sure we don't include ui/aura/window_property.h
1915 in header files.
1916 """
1917 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1918 errors = []
1919 for f in input_api.AffectedFiles():
1920 if not f.LocalPath().endswith('.h'):
1921 continue
1922 for line_num, line in f.ChangedContents():
1923 if pattern.match(line):
1924 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491925
Sam Maiera6e76d72022-02-11 21:43:501926 results = []
1927 if errors:
1928 results.append(
1929 output_api.PresubmitError(
1930 'Header files should not include ui/aura/window_property.h',
1931 errors))
1932 return results
[email protected]c8278b32012-10-30 20:35:491933
1934
Omer Katzcc77ea92021-04-26 10:23:281935def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501936 """Makes sure we don't include any headers from
1937 third_party/blink/renderer/platform/heap/impl or
1938 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1939 third_party/blink/renderer/platform/heap
1940 """
1941 impl_pattern = input_api.re.compile(
1942 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1943 v8_wrapper_pattern = input_api.re.compile(
1944 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1945 )
1946 file_filter = lambda f: not input_api.re.match(
1947 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1948 f.LocalPath())
1949 errors = []
Omer Katzcc77ea92021-04-26 10:23:281950
Sam Maiera6e76d72022-02-11 21:43:501951 for f in input_api.AffectedFiles(file_filter=file_filter):
1952 for line_num, line in f.ChangedContents():
1953 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1954 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281955
Sam Maiera6e76d72022-02-11 21:43:501956 results = []
1957 if errors:
1958 results.append(
1959 output_api.PresubmitError(
1960 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1961 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1962 'relevant counterparts from third_party/blink/renderer/platform/heap',
1963 errors))
1964 return results
Omer Katzcc77ea92021-04-26 10:23:281965
1966
[email protected]70ca77752012-11-20 03:45:031967def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501968 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1969 errors = []
1970 for line_num, line in f.ChangedContents():
1971 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1972 # First-level headers in markdown look a lot like version control
1973 # conflict markers. http://daringfireball.net/projects/markdown/basics
1974 continue
1975 if pattern.match(line):
1976 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1977 return errors
[email protected]70ca77752012-11-20 03:45:031978
1979
Saagar Sanghavifceeaae2020-08-12 16:40:361980def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501981 """Usually this is not intentional and will cause a compile failure."""
1982 errors = []
1983 for f in input_api.AffectedFiles():
1984 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031985
Sam Maiera6e76d72022-02-11 21:43:501986 results = []
1987 if errors:
1988 results.append(
1989 output_api.PresubmitError(
1990 'Version control conflict markers found, please resolve.',
1991 errors))
1992 return results
[email protected]70ca77752012-11-20 03:45:031993
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201994
Saagar Sanghavifceeaae2020-08-12 16:40:361995def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501996 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1997 errors = []
1998 for f in input_api.AffectedFiles():
1999 for line_num, line in f.ChangedContents():
2000 if pattern.search(line):
2001 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162002
Sam Maiera6e76d72022-02-11 21:43:502003 results = []
2004 if errors:
2005 results.append(
2006 output_api.PresubmitPromptWarning(
2007 'Found Google support URL addressed by answer number. Please replace '
2008 'with a p= identifier instead. See crbug.com/679462\n',
2009 errors))
2010 return results
estadee17314a02017-01-12 16:22:162011
[email protected]70ca77752012-11-20 03:45:032012
Saagar Sanghavifceeaae2020-08-12 16:40:362013def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502014 def FilterFile(affected_file):
2015 """Filter function for use with input_api.AffectedSourceFiles,
2016 below. This filters out everything except non-test files from
2017 top-level directories that generally speaking should not hard-code
2018 service URLs (e.g. src/android_webview/, src/content/ and others).
2019 """
2020 return input_api.FilterSourceFile(
2021 affected_file,
2022 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2023 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2024 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442025
Sam Maiera6e76d72022-02-11 21:43:502026 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2027 '\.(com|net)[^"]*"')
2028 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2029 pattern = input_api.re.compile(base_pattern)
2030 problems = [] # items are (filename, line_number, line)
2031 for f in input_api.AffectedSourceFiles(FilterFile):
2032 for line_num, line in f.ChangedContents():
2033 if not comment_pattern.search(line) and pattern.search(line):
2034 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442035
Sam Maiera6e76d72022-02-11 21:43:502036 if problems:
2037 return [
2038 output_api.PresubmitPromptOrNotify(
2039 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2040 'Are you sure this is correct?', [
2041 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2042 for problem in problems
2043 ])
2044 ]
2045 else:
2046 return []
[email protected]06e6d0ff2012-12-11 01:36:442047
2048
Saagar Sanghavifceeaae2020-08-12 16:40:362049def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502050 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292051
Sam Maiera6e76d72022-02-11 21:43:502052 def FileFilter(affected_file):
2053 """Includes directories known to be Chrome OS only."""
2054 return input_api.FilterSourceFile(
2055 affected_file,
2056 files_to_check=(
2057 '^ash/',
2058 '^chromeos/', # Top-level src/chromeos.
2059 '.*/chromeos/', # Any path component.
2060 '^components/arc',
2061 '^components/exo'),
2062 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292063
Sam Maiera6e76d72022-02-11 21:43:502064 prefs = []
2065 priority_prefs = []
2066 for f in input_api.AffectedFiles(file_filter=FileFilter):
2067 for line_num, line in f.ChangedContents():
2068 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2069 line):
2070 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2071 prefs.append(' %s' % line)
2072 if input_api.re.search(
2073 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2074 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2075 priority_prefs.append(' %s' % line)
2076
2077 results = []
2078 if (prefs):
2079 results.append(
2080 output_api.PresubmitPromptWarning(
2081 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2082 'by browser sync settings. If these prefs should be controlled by OS '
2083 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2084 '\n'.join(prefs)))
2085 if (priority_prefs):
2086 results.append(
2087 output_api.PresubmitPromptWarning(
2088 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2089 'controlled by browser sync settings. If these prefs should be '
2090 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2091 'instead.\n' + '\n'.join(prefs)))
2092 return results
James Cook6b6597c2019-11-06 22:05:292093
2094
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492095# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362096def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502097 """Makes sure there are no abbreviations in the name of PNG files.
2098 The native_client_sdk directory is excluded because it has auto-generated PNG
2099 files for documentation.
2100 """
2101 errors = []
2102 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2103 files_to_skip = [r'^native_client_sdk[\\/]']
2104 file_filter = lambda f: input_api.FilterSourceFile(
2105 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2106 for f in input_api.AffectedFiles(include_deletes=False,
2107 file_filter=file_filter):
2108 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272109
Sam Maiera6e76d72022-02-11 21:43:502110 results = []
2111 if errors:
2112 results.append(
2113 output_api.PresubmitError(
2114 'The name of PNG files should not have abbreviations. \n'
2115 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2116 'Contact [email protected] if you have questions.', errors))
2117 return results
[email protected]d2530012013-01-25 16:39:272118
2119
Daniel Cheng4dcdb6b2017-04-13 08:30:172120def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502121 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172122
Sam Maiera6e76d72022-02-11 21:43:502123 Args:
2124 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2125 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172126 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502127 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172128 if rule.startswith('+') or rule.startswith('!')
2129 ])
Sam Maiera6e76d72022-02-11 21:43:502130 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2131 add_rules.update([
2132 rule[1:] for rule in rules
2133 if rule.startswith('+') or rule.startswith('!')
2134 ])
2135 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172136
2137
2138def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502139 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172140
Sam Maiera6e76d72022-02-11 21:43:502141 # Stubs for handling special syntax in the root DEPS file.
2142 class _VarImpl:
2143 def __init__(self, local_scope):
2144 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172145
Sam Maiera6e76d72022-02-11 21:43:502146 def Lookup(self, var_name):
2147 """Implements the Var syntax."""
2148 try:
2149 return self._local_scope['vars'][var_name]
2150 except KeyError:
2151 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172152
Sam Maiera6e76d72022-02-11 21:43:502153 local_scope = {}
2154 global_scope = {
2155 'Var': _VarImpl(local_scope).Lookup,
2156 'Str': str,
2157 }
Dirk Pranke1b9e06382021-05-14 01:16:222158
Sam Maiera6e76d72022-02-11 21:43:502159 exec(contents, global_scope, local_scope)
2160 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172161
2162
2163def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502164 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2165 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412166
Sam Maiera6e76d72022-02-11 21:43:502167 For a directory (rather than a specific filename) we fake a path to
2168 a specific filename by adding /DEPS. This is chosen as a file that
2169 will seldom or never be subject to per-file include_rules.
2170 """
2171 # We ignore deps entries on auto-generated directories.
2172 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082173
Sam Maiera6e76d72022-02-11 21:43:502174 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2175 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172176
Sam Maiera6e76d72022-02-11 21:43:502177 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172178
Sam Maiera6e76d72022-02-11 21:43:502179 results = set()
2180 for added_dep in added_deps:
2181 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2182 continue
2183 # Assume that a rule that ends in .h is a rule for a specific file.
2184 if added_dep.endswith('.h'):
2185 results.add(added_dep)
2186 else:
2187 results.add(os_path.join(added_dep, 'DEPS'))
2188 return results
[email protected]f32e2d1e2013-07-26 21:39:082189
2190
Saagar Sanghavifceeaae2020-08-12 16:40:362191def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502192 """When a dependency prefixed with + is added to a DEPS file, we
2193 want to make sure that the change is reviewed by an OWNER of the
2194 target file or directory, to avoid layering violations from being
2195 introduced. This check verifies that this happens.
2196 """
2197 # We rely on Gerrit's code-owners to check approvals.
2198 # input_api.gerrit is always set for Chromium, but other projects
2199 # might not use Gerrit.
2200 if not input_api.gerrit:
2201 return []
2202 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2203 input_api.change.issue)):
2204 # Skip OWNERS check when Owners-Override label is approved. This is intended
2205 # for global owners, trusted bots, and on-call sheriffs. Review is still
2206 # required for these changes.
2207 return []
Edward Lesmes6fba51082021-01-20 04:20:232208
Sam Maiera6e76d72022-02-11 21:43:502209 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242210
Sam Maiera6e76d72022-02-11 21:43:502211 file_filter = lambda f: not input_api.re.match(
2212 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2213 for f in input_api.AffectedFiles(include_deletes=False,
2214 file_filter=file_filter):
2215 filename = input_api.os_path.basename(f.LocalPath())
2216 if filename == 'DEPS':
2217 virtual_depended_on_files.update(
2218 _CalculateAddedDeps(input_api.os_path,
2219 '\n'.join(f.OldContents()),
2220 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552221
Sam Maiera6e76d72022-02-11 21:43:502222 if not virtual_depended_on_files:
2223 return []
[email protected]e871964c2013-05-13 14:14:552224
Sam Maiera6e76d72022-02-11 21:43:502225 if input_api.is_committing:
2226 if input_api.tbr:
2227 return [
2228 output_api.PresubmitNotifyResult(
2229 '--tbr was specified, skipping OWNERS check for DEPS additions'
2230 )
2231 ]
2232 if input_api.dry_run:
2233 return [
2234 output_api.PresubmitNotifyResult(
2235 'This is a dry run, skipping OWNERS check for DEPS additions'
2236 )
2237 ]
2238 if not input_api.change.issue:
2239 return [
2240 output_api.PresubmitError(
2241 "DEPS approval by OWNERS check failed: this change has "
2242 "no change number, so we can't check it for approvals.")
2243 ]
2244 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412245 else:
Sam Maiera6e76d72022-02-11 21:43:502246 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552247
Sam Maiera6e76d72022-02-11 21:43:502248 owner_email, reviewers = (
2249 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2250 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552251
Sam Maiera6e76d72022-02-11 21:43:502252 owner_email = owner_email or input_api.change.author_email
2253
2254 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2255 virtual_depended_on_files, reviewers.union([owner_email]), [])
2256 missing_files = [
2257 f for f in virtual_depended_on_files
2258 if approval_status[f] != input_api.owners_client.APPROVED
2259 ]
2260
2261 # We strip the /DEPS part that was added by
2262 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2263 # directory.
2264 def StripDeps(path):
2265 start_deps = path.rfind('/DEPS')
2266 if start_deps != -1:
2267 return path[:start_deps]
2268 else:
2269 return path
2270
2271 unapproved_dependencies = [
2272 "'+%s'," % StripDeps(path) for path in missing_files
2273 ]
2274
2275 if unapproved_dependencies:
2276 output_list = [
2277 output(
2278 'You need LGTM from owners of depends-on paths in DEPS that were '
2279 'modified in this CL:\n %s' %
2280 '\n '.join(sorted(unapproved_dependencies)))
2281 ]
2282 suggested_owners = input_api.owners_client.SuggestOwners(
2283 missing_files, exclude=[owner_email])
2284 output_list.append(
2285 output('Suggested missing target path OWNERS:\n %s' %
2286 '\n '.join(suggested_owners or [])))
2287 return output_list
2288
2289 return []
[email protected]e871964c2013-05-13 14:14:552290
2291
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492292# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362293def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502294 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2295 files_to_skip = (
2296 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2297 input_api.DEFAULT_FILES_TO_SKIP + (
2298 r"^base[\\/]logging\.h$",
2299 r"^base[\\/]logging\.cc$",
2300 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2301 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2302 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2303 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2304 r"startup_browser_creator\.cc$",
2305 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2306 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2307 r"diagnostics_writer\.cc$",
2308 r"^chrome[\\/]chrome_cleaner[\\/].*",
2309 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2310 r"dll_hash_main\.cc$",
2311 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2312 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502313 r"^components[\\/]browser_watcher[\\/]"
2314 r"dump_stability_report_main_win.cc$",
2315 r"^components[\\/]media_control[\\/]renderer[\\/]"
2316 r"media_playback_options\.cc$",
2317 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2318 r"overlay_strategy_underlay_cast\.cc$",
2319 r"^components[\\/]zucchini[\\/].*",
2320 # TODO(peter): Remove exception. https://crbug.com/534537
2321 r"^content[\\/]browser[\\/]notifications[\\/]"
2322 r"notification_event_dispatcher_impl\.cc$",
2323 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2324 r"gl_helper_benchmark\.cc$",
2325 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2326 r"^courgette[\\/]courgette_tool\.cc$",
2327 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2328 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2329 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2330 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2331 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2332 r"^ipc[\\/]ipc_logging\.cc$",
2333 r"^native_client_sdk[\\/]",
2334 r"^remoting[\\/]base[\\/]logging\.h$",
2335 r"^remoting[\\/]host[\\/].*",
2336 r"^sandbox[\\/]linux[\\/].*",
2337 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2338 r"dump_file_system.cc$",
2339 r"^tools[\\/]",
2340 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2341 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2342 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2343 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2344 r"xwmstartupcheck\.cc$"))
2345 source_file_filter = lambda x: input_api.FilterSourceFile(
2346 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402347
Sam Maiera6e76d72022-02-11 21:43:502348 log_info = set([])
2349 printf = set([])
[email protected]85218562013-11-22 07:41:402350
Sam Maiera6e76d72022-02-11 21:43:502351 for f in input_api.AffectedSourceFiles(source_file_filter):
2352 for _, line in f.ChangedContents():
2353 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2354 log_info.add(f.LocalPath())
2355 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2356 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372357
Sam Maiera6e76d72022-02-11 21:43:502358 if input_api.re.search(r"\bprintf\(", line):
2359 printf.add(f.LocalPath())
2360 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2361 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402362
Sam Maiera6e76d72022-02-11 21:43:502363 if log_info:
2364 return [
2365 output_api.PresubmitError(
2366 'These files spam the console log with LOG(INFO):',
2367 items=log_info)
2368 ]
2369 if printf:
2370 return [
2371 output_api.PresubmitError(
2372 'These files spam the console log with printf/fprintf:',
2373 items=printf)
2374 ]
2375 return []
[email protected]85218562013-11-22 07:41:402376
2377
Saagar Sanghavifceeaae2020-08-12 16:40:362378def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502379 """These types are all expected to hold locks while in scope and
2380 so should never be anonymous (which causes them to be immediately
2381 destroyed)."""
2382 they_who_must_be_named = [
2383 'base::AutoLock',
2384 'base::AutoReset',
2385 'base::AutoUnlock',
2386 'SkAutoAlphaRestore',
2387 'SkAutoBitmapShaderInstall',
2388 'SkAutoBlitterChoose',
2389 'SkAutoBounderCommit',
2390 'SkAutoCallProc',
2391 'SkAutoCanvasRestore',
2392 'SkAutoCommentBlock',
2393 'SkAutoDescriptor',
2394 'SkAutoDisableDirectionCheck',
2395 'SkAutoDisableOvalCheck',
2396 'SkAutoFree',
2397 'SkAutoGlyphCache',
2398 'SkAutoHDC',
2399 'SkAutoLockColors',
2400 'SkAutoLockPixels',
2401 'SkAutoMalloc',
2402 'SkAutoMaskFreeImage',
2403 'SkAutoMutexAcquire',
2404 'SkAutoPathBoundsUpdate',
2405 'SkAutoPDFRelease',
2406 'SkAutoRasterClipValidate',
2407 'SkAutoRef',
2408 'SkAutoTime',
2409 'SkAutoTrace',
2410 'SkAutoUnref',
2411 ]
2412 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2413 # bad: base::AutoLock(lock.get());
2414 # not bad: base::AutoLock lock(lock.get());
2415 bad_pattern = input_api.re.compile(anonymous)
2416 # good: new base::AutoLock(lock.get())
2417 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2418 errors = []
[email protected]49aa76a2013-12-04 06:59:162419
Sam Maiera6e76d72022-02-11 21:43:502420 for f in input_api.AffectedFiles():
2421 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2422 continue
2423 for linenum, line in f.ChangedContents():
2424 if bad_pattern.search(line) and not good_pattern.search(line):
2425 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162426
Sam Maiera6e76d72022-02-11 21:43:502427 if errors:
2428 return [
2429 output_api.PresubmitError(
2430 'These lines create anonymous variables that need to be named:',
2431 items=errors)
2432 ]
2433 return []
[email protected]49aa76a2013-12-04 06:59:162434
2435
Saagar Sanghavifceeaae2020-08-12 16:40:362436def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502437 # Returns whether |template_str| is of the form <T, U...> for some types T
2438 # and U. Assumes that |template_str| is already in the form <...>.
2439 def HasMoreThanOneArg(template_str):
2440 # Level of <...> nesting.
2441 nesting = 0
2442 for c in template_str:
2443 if c == '<':
2444 nesting += 1
2445 elif c == '>':
2446 nesting -= 1
2447 elif c == ',' and nesting == 1:
2448 return True
2449 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532450
Sam Maiera6e76d72022-02-11 21:43:502451 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2452 sources = lambda affected_file: input_api.FilterSourceFile(
2453 affected_file,
2454 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2455 DEFAULT_FILES_TO_SKIP),
2456 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552457
Sam Maiera6e76d72022-02-11 21:43:502458 # Pattern to capture a single "<...>" block of template arguments. It can
2459 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2460 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2461 # latter would likely require counting that < and > match, which is not
2462 # expressible in regular languages. Should the need arise, one can introduce
2463 # limited counting (matching up to a total number of nesting depth), which
2464 # should cover all practical cases for already a low nesting limit.
2465 template_arg_pattern = (
2466 r'<[^>]*' # Opening block of <.
2467 r'>([^<]*>)?') # Closing block of >.
2468 # Prefix expressing that whatever follows is not already inside a <...>
2469 # block.
2470 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2471 null_construct_pattern = input_api.re.compile(
2472 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2473 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552474
Sam Maiera6e76d72022-02-11 21:43:502475 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2476 template_arg_no_array_pattern = (
2477 r'<[^>]*[^]]' # Opening block of <.
2478 r'>([^(<]*[^]]>)?') # Closing block of >.
2479 # Prefix saying that what follows is the start of an expression.
2480 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2481 # Suffix saying that what follows are call parentheses with a non-empty list
2482 # of arguments.
2483 nonempty_arg_list_pattern = r'\(([^)]|$)'
2484 # Put the template argument into a capture group for deeper examination later.
2485 return_construct_pattern = input_api.re.compile(
2486 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2487 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552488
Sam Maiera6e76d72022-02-11 21:43:502489 problems_constructor = []
2490 problems_nullptr = []
2491 for f in input_api.AffectedSourceFiles(sources):
2492 for line_number, line in f.ChangedContents():
2493 # Disallow:
2494 # return std::unique_ptr<T>(foo);
2495 # bar = std::unique_ptr<T>(foo);
2496 # But allow:
2497 # return std::unique_ptr<T[]>(foo);
2498 # bar = std::unique_ptr<T[]>(foo);
2499 # And also allow cases when the second template argument is present. Those
2500 # cases cannot be handled by std::make_unique:
2501 # return std::unique_ptr<T, U>(foo);
2502 # bar = std::unique_ptr<T, U>(foo);
2503 local_path = f.LocalPath()
2504 return_construct_result = return_construct_pattern.search(line)
2505 if return_construct_result and not HasMoreThanOneArg(
2506 return_construct_result.group('template_arg')):
2507 problems_constructor.append(
2508 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2509 # Disallow:
2510 # std::unique_ptr<T>()
2511 if null_construct_pattern.search(line):
2512 problems_nullptr.append(
2513 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052514
Sam Maiera6e76d72022-02-11 21:43:502515 errors = []
2516 if problems_nullptr:
2517 errors.append(
2518 output_api.PresubmitPromptWarning(
2519 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2520 problems_nullptr))
2521 if problems_constructor:
2522 errors.append(
2523 output_api.PresubmitError(
2524 'The following files use explicit std::unique_ptr constructor. '
2525 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2526 'std::make_unique is not an option.', problems_constructor))
2527 return errors
Peter Kasting4844e46e2018-02-23 07:27:102528
2529
Saagar Sanghavifceeaae2020-08-12 16:40:362530def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502531 """Checks if any new user action has been added."""
2532 if any('actions.xml' == input_api.os_path.basename(f)
2533 for f in input_api.LocalPaths()):
2534 # If actions.xml is already included in the changelist, the PRESUBMIT
2535 # for actions.xml will do a more complete presubmit check.
2536 return []
2537
2538 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2539 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2540 input_api.DEFAULT_FILES_TO_SKIP)
2541 file_filter = lambda f: input_api.FilterSourceFile(
2542 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2543
2544 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2545 current_actions = None
2546 for f in input_api.AffectedFiles(file_filter=file_filter):
2547 for line_num, line in f.ChangedContents():
2548 match = input_api.re.search(action_re, line)
2549 if match:
2550 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2551 # loaded only once.
2552 if not current_actions:
2553 with open(
2554 'tools/metrics/actions/actions.xml') as actions_f:
2555 current_actions = actions_f.read()
2556 # Search for the matched user action name in |current_actions|.
2557 for action_name in match.groups():
2558 action = 'name="{0}"'.format(action_name)
2559 if action not in current_actions:
2560 return [
2561 output_api.PresubmitPromptWarning(
2562 'File %s line %d: %s is missing in '
2563 'tools/metrics/actions/actions.xml. Please run '
2564 'tools/metrics/actions/extract_actions.py to update.'
2565 % (f.LocalPath(), line_num, action_name))
2566 ]
[email protected]999261d2014-03-03 20:08:082567 return []
2568
[email protected]999261d2014-03-03 20:08:082569
Daniel Cheng13ca61a882017-08-25 15:11:252570def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502571 import sys
2572 sys.path = sys.path + [
2573 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2574 'json_comment_eater')
2575 ]
2576 import json_comment_eater
2577 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252578
2579
[email protected]99171a92014-06-03 08:44:472580def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172581 try:
Sam Maiera6e76d72022-02-11 21:43:502582 contents = input_api.ReadFile(filename)
2583 if eat_comments:
2584 json_comment_eater = _ImportJSONCommentEater(input_api)
2585 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172586
Sam Maiera6e76d72022-02-11 21:43:502587 input_api.json.loads(contents)
2588 except ValueError as e:
2589 return e
Andrew Grieve4deedb12022-02-03 21:34:502590 return None
2591
2592
Sam Maiera6e76d72022-02-11 21:43:502593def _GetIDLParseError(input_api, filename):
2594 try:
2595 contents = input_api.ReadFile(filename)
2596 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2597 'tools', 'json_schema_compiler',
2598 'idl_schema.py')
2599 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282600 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502601 stdin=input_api.subprocess.PIPE,
2602 stdout=input_api.subprocess.PIPE,
2603 stderr=input_api.subprocess.PIPE,
2604 universal_newlines=True)
2605 (_, error) = process.communicate(input=contents)
2606 return error or None
2607 except ValueError as e:
2608 return e
agrievef32bcc72016-04-04 14:57:402609
agrievef32bcc72016-04-04 14:57:402610
Sam Maiera6e76d72022-02-11 21:43:502611def CheckParseErrors(input_api, output_api):
2612 """Check that IDL and JSON files do not contain syntax errors."""
2613 actions = {
2614 '.idl': _GetIDLParseError,
2615 '.json': _GetJSONParseError,
2616 }
2617 # Most JSON files are preprocessed and support comments, but these do not.
2618 json_no_comments_patterns = [
2619 r'^testing[\\/]',
2620 ]
2621 # Only run IDL checker on files in these directories.
2622 idl_included_patterns = [
2623 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2624 r'^extensions[\\/]common[\\/]api[\\/]',
2625 ]
agrievef32bcc72016-04-04 14:57:402626
Sam Maiera6e76d72022-02-11 21:43:502627 def get_action(affected_file):
2628 filename = affected_file.LocalPath()
2629 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402630
Sam Maiera6e76d72022-02-11 21:43:502631 def FilterFile(affected_file):
2632 action = get_action(affected_file)
2633 if not action:
2634 return False
2635 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402636
Sam Maiera6e76d72022-02-11 21:43:502637 if _MatchesFile(input_api,
2638 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2639 return False
2640
2641 if (action == _GetIDLParseError
2642 and not _MatchesFile(input_api, idl_included_patterns, path)):
2643 return False
2644 return True
2645
2646 results = []
2647 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2648 include_deletes=False):
2649 action = get_action(affected_file)
2650 kwargs = {}
2651 if (action == _GetJSONParseError
2652 and _MatchesFile(input_api, json_no_comments_patterns,
2653 affected_file.LocalPath())):
2654 kwargs['eat_comments'] = False
2655 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2656 **kwargs)
2657 if parse_error:
2658 results.append(
2659 output_api.PresubmitError(
2660 '%s could not be parsed: %s' %
2661 (affected_file.LocalPath(), parse_error)))
2662 return results
2663
2664
2665def CheckJavaStyle(input_api, output_api):
2666 """Runs checkstyle on changed java files and returns errors if any exist."""
2667
2668 # Return early if no java files were modified.
2669 if not any(
2670 _IsJavaFile(input_api, f.LocalPath())
2671 for f in input_api.AffectedFiles()):
2672 return []
2673
2674 import sys
2675 original_sys_path = sys.path
2676 try:
2677 sys.path = sys.path + [
2678 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2679 'android', 'checkstyle')
2680 ]
2681 import checkstyle
2682 finally:
2683 # Restore sys.path to what it was before.
2684 sys.path = original_sys_path
2685
2686 return checkstyle.RunCheckstyle(
2687 input_api,
2688 output_api,
2689 'tools/android/checkstyle/chromium-style-5.0.xml',
2690 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2691
2692
2693def CheckPythonDevilInit(input_api, output_api):
2694 """Checks to make sure devil is initialized correctly in python scripts."""
2695 script_common_initialize_pattern = input_api.re.compile(
2696 r'script_common\.InitializeEnvironment\(')
2697 devil_env_config_initialize = input_api.re.compile(
2698 r'devil_env\.config\.Initialize\(')
2699
2700 errors = []
2701
2702 sources = lambda affected_file: input_api.FilterSourceFile(
2703 affected_file,
2704 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2705 r'^build[\\/]android[\\/]devil_chromium\.py',
2706 r'^third_party[\\/].*',
2707 )),
2708 files_to_check=[r'.*\.py$'])
2709
2710 for f in input_api.AffectedSourceFiles(sources):
2711 for line_num, line in f.ChangedContents():
2712 if (script_common_initialize_pattern.search(line)
2713 or devil_env_config_initialize.search(line)):
2714 errors.append("%s:%d" % (f.LocalPath(), line_num))
2715
2716 results = []
2717
2718 if errors:
2719 results.append(
2720 output_api.PresubmitError(
2721 'Devil initialization should always be done using '
2722 'devil_chromium.Initialize() in the chromium project, to use better '
2723 'defaults for dependencies (ex. up-to-date version of adb).',
2724 errors))
2725
2726 return results
2727
2728
2729def _MatchesFile(input_api, patterns, path):
2730 for pattern in patterns:
2731 if input_api.re.search(pattern, path):
2732 return True
2733 return False
2734
2735
2736def _GetOwnersFilesToCheckForIpcOwners(input_api):
2737 """Gets a list of OWNERS files to check for correct security owners.
2738
2739 Returns:
2740 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2741 contain to cover IPC-related files with noparent reviewer rules.
2742 """
2743 # Whether or not a file affects IPC is (mostly) determined by a simple list
2744 # of filename patterns.
2745 file_patterns = [
2746 # Legacy IPC:
2747 '*_messages.cc',
2748 '*_messages*.h',
2749 '*_param_traits*.*',
2750 # Mojo IPC:
2751 '*.mojom',
2752 '*_mojom_traits*.*',
2753 '*_struct_traits*.*',
2754 '*_type_converter*.*',
2755 '*.typemap',
2756 # Android native IPC:
2757 '*.aidl',
2758 # Blink uses a different file naming convention:
2759 '*EnumTraits*.*',
2760 "*MojomTraits*.*",
2761 '*StructTraits*.*',
2762 '*TypeConverter*.*',
2763 ]
2764
2765 # These third_party directories do not contain IPCs, but contain files
2766 # matching the above patterns, which trigger false positives.
2767 exclude_paths = [
2768 'third_party/crashpad/*',
2769 'third_party/blink/renderer/platform/bindings/*',
2770 'third_party/protobuf/benchmarks/python/*',
2771 'third_party/win_build_output/*',
2772 # These files are just used to communicate between class loaders running
2773 # in the same process.
2774 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2775 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2776 ]
2777
2778 # Dictionary mapping an OWNERS file path to Patterns.
2779 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2780 # rules ) to a PatternEntry.
2781 # PatternEntry is a dictionary with two keys:
2782 # - 'files': the files that are matched by this pattern
2783 # - 'rules': the per-file rules needed for this pattern
2784 # For example, if we expect OWNERS file to contain rules for *.mojom and
2785 # *_struct_traits*.*, Patterns might look like this:
2786 # {
2787 # '*.mojom': {
2788 # 'files': ...,
2789 # 'rules': [
2790 # 'per-file *.mojom=set noparent',
2791 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2792 # ],
2793 # },
2794 # '*_struct_traits*.*': {
2795 # 'files': ...,
2796 # 'rules': [
2797 # 'per-file *_struct_traits*.*=set noparent',
2798 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2799 # ],
2800 # },
2801 # }
2802 to_check = {}
2803
2804 def AddPatternToCheck(input_file, pattern):
2805 owners_file = input_api.os_path.join(
2806 input_api.os_path.dirname(input_file.AbsoluteLocalPath()),
2807 'OWNERS')
2808 if owners_file not in to_check:
2809 to_check[owners_file] = {}
2810 if pattern not in to_check[owners_file]:
2811 to_check[owners_file][pattern] = {
2812 'files': [],
2813 'rules': [
2814 'per-file %s=set noparent' % pattern,
2815 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2816 ]
2817 }
2818 to_check[owners_file][pattern]['files'].append(input_file)
2819
2820 # Iterate through the affected files to see what we actually need to check
2821 # for. We should only nag patch authors about per-file rules if a file in that
2822 # directory would match that pattern. If a directory only contains *.mojom
2823 # files and no *_messages*.h files, we should only nag about rules for
2824 # *.mojom files.
2825 for f in input_api.AffectedFiles(include_deletes=False):
2826 # Manifest files don't have a strong naming convention. Instead, try to find
2827 # affected .cc and .h files which look like they contain a manifest
2828 # definition.
2829 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2830 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2831 if (manifest_pattern.search(f.LocalPath())
2832 and not test_manifest_pattern.search(f.LocalPath())):
2833 # We expect all actual service manifest files to contain at least one
2834 # qualified reference to service_manager::Manifest.
2835 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2836 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
2837 for pattern in file_patterns:
2838 if input_api.fnmatch.fnmatch(
2839 input_api.os_path.basename(f.LocalPath()), pattern):
2840 skip = False
2841 for exclude in exclude_paths:
2842 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2843 skip = True
2844 break
2845 if skip:
2846 continue
2847 AddPatternToCheck(f, pattern)
2848 break
2849
2850 return to_check
2851
2852
2853def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2854 """Adds OWNERS files to check for correct Fuchsia security owners."""
2855
2856 file_patterns = [
2857 # Component specifications.
2858 '*.cml', # Component Framework v2.
2859 '*.cmx', # Component Framework v1.
2860
2861 # Fuchsia IDL protocol specifications.
2862 '*.fidl',
2863 ]
2864
2865 # Don't check for owners files for changes in these directories.
2866 exclude_paths = [
2867 'third_party/crashpad/*',
2868 ]
2869
2870 def AddPatternToCheck(input_file, pattern):
2871 owners_file = input_api.os_path.join(
2872 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2873 if owners_file not in to_check:
2874 to_check[owners_file] = {}
2875 if pattern not in to_check[owners_file]:
2876 to_check[owners_file][pattern] = {
2877 'files': [],
2878 'rules': [
2879 'per-file %s=set noparent' % pattern,
2880 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2881 ]
2882 }
2883 to_check[owners_file][pattern]['files'].append(input_file)
2884
2885 # Iterate through the affected files to see what we actually need to check
2886 # for. We should only nag patch authors about per-file rules if a file in that
2887 # directory would match that pattern.
2888 for f in input_api.AffectedFiles(include_deletes=False):
2889 skip = False
2890 for exclude in exclude_paths:
2891 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2892 skip = True
2893 if skip:
2894 continue
2895
2896 for pattern in file_patterns:
2897 if input_api.fnmatch.fnmatch(
2898 input_api.os_path.basename(f.LocalPath()), pattern):
2899 AddPatternToCheck(f, pattern)
2900 break
2901
2902 return to_check
2903
2904
2905def CheckSecurityOwners(input_api, output_api):
2906 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2907 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2908 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
2909
2910 if to_check:
2911 # If there are any OWNERS files to check, there are IPC-related changes in
2912 # this CL. Auto-CC the review list.
2913 output_api.AppendCC('[email protected]')
2914
2915 # Go through the OWNERS files to check, filtering out rules that are already
2916 # present in that OWNERS file.
2917 for owners_file, patterns in to_check.items():
2918 try:
2919 with open(owners_file) as f:
2920 lines = set(f.read().splitlines())
2921 for entry in patterns.values():
2922 entry['rules'] = [
2923 rule for rule in entry['rules'] if rule not in lines
2924 ]
2925 except IOError:
2926 # No OWNERS file, so all the rules are definitely missing.
2927 continue
2928
2929 # All the remaining lines weren't found in OWNERS files, so emit an error.
2930 errors = []
2931 for owners_file, patterns in to_check.items():
2932 missing_lines = []
2933 files = []
2934 for _, entry in patterns.items():
2935 missing_lines.extend(entry['rules'])
2936 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2937 if missing_lines:
2938 errors.append('Because of the presence of files:\n%s\n\n'
2939 '%s needs the following %d lines added:\n\n%s' %
2940 ('\n'.join(files), owners_file, len(missing_lines),
2941 '\n'.join(missing_lines)))
2942
2943 results = []
2944 if errors:
2945 if input_api.is_committing:
2946 output = output_api.PresubmitError
2947 else:
2948 output = output_api.PresubmitPromptWarning
2949 results.append(
2950 output(
2951 'Found OWNERS files that need to be updated for IPC security '
2952 + 'review coverage.\nPlease update the OWNERS files below:',
2953 long_text='\n\n'.join(errors)))
2954
2955 return results
2956
2957
2958def _GetFilesUsingSecurityCriticalFunctions(input_api):
2959 """Checks affected files for changes to security-critical calls. This
2960 function checks the full change diff, to catch both additions/changes
2961 and removals.
2962
2963 Returns a dict keyed by file name, and the value is a set of detected
2964 functions.
2965 """
2966 # Map of function pretty name (displayed in an error) to the pattern to
2967 # match it with.
2968 _PATTERNS_TO_CHECK = {
2969 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
2970 }
2971 _PATTERNS_TO_CHECK = {
2972 k: input_api.re.compile(v)
2973 for k, v in _PATTERNS_TO_CHECK.items()
2974 }
2975
John Budorick47ca3fe2018-02-10 00:53:102976 import os
2977
Sam Maiera6e76d72022-02-11 21:43:502978 # We don't want to trigger on strings within this file.
2979 def presubmit_file_filter(f):
2980 return 'PRESUBMIT.py' != os.path.split(f.LocalPath())[1]
2981
2982 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2983 files_to_functions = {}
2984 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
2985 diff = f.GenerateScmDiff()
2986 for line in diff.split('\n'):
2987 # Not using just RightHandSideLines() because removing a
2988 # call to a security-critical function can be just as important
2989 # as adding or changing the arguments.
2990 if line.startswith('-') or (line.startswith('+')
2991 and not line.startswith('++')):
2992 for name, pattern in _PATTERNS_TO_CHECK.items():
2993 if pattern.search(line):
2994 path = f.LocalPath()
2995 if not path in files_to_functions:
2996 files_to_functions[path] = set()
2997 files_to_functions[path].add(name)
2998 return files_to_functions
2999
3000
3001def CheckSecurityChanges(input_api, output_api):
3002 """Checks that changes involving security-critical functions are reviewed
3003 by the security team.
3004 """
3005 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3006 if not len(files_to_functions):
3007 return []
3008
3009 owner_email, reviewers = (
3010 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3011 input_api, None, approval_needed=input_api.is_committing))
3012
3013 # Load the OWNERS file for security changes.
3014 owners_file = 'ipc/SECURITY_OWNERS'
3015 security_owners = input_api.owners_client.ListOwners(owners_file)
3016 has_security_owner = any([owner in reviewers for owner in security_owners])
3017 if has_security_owner:
3018 return []
3019
3020 msg = 'The following files change calls to security-sensive functions\n' \
3021 'that need to be reviewed by {}.\n'.format(owners_file)
3022 for path, names in files_to_functions.items():
3023 msg += ' {}\n'.format(path)
3024 for name in names:
3025 msg += ' {}\n'.format(name)
3026 msg += '\n'
3027
3028 if input_api.is_committing:
3029 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033030 else:
Sam Maiera6e76d72022-02-11 21:43:503031 output = output_api.PresubmitNotifyResult
3032 return [output(msg)]
3033
3034
3035def CheckSetNoParent(input_api, output_api):
3036 """Checks that set noparent is only used together with an OWNERS file in
3037 //build/OWNERS.setnoparent (see also
3038 //docs/code_reviews.md#owners-files-details)
3039 """
3040 # Return early if no OWNERS files were modified.
3041 if not any(f.LocalPath().endswith('OWNERS')
3042 for f in input_api.AffectedFiles(include_deletes=False)):
3043 return []
3044
3045 errors = []
3046
3047 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3048 allowed_owners_files = set()
3049 with open(allowed_owners_files_file, 'r') as f:
3050 for line in f:
3051 line = line.strip()
3052 if not line or line.startswith('#'):
3053 continue
3054 allowed_owners_files.add(line)
3055
3056 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3057
3058 for f in input_api.AffectedFiles(include_deletes=False):
3059 if not f.LocalPath().endswith('OWNERS'):
3060 continue
3061
3062 found_owners_files = set()
3063 found_set_noparent_lines = dict()
3064
3065 # Parse the OWNERS file.
3066 for lineno, line in enumerate(f.NewContents(), 1):
3067 line = line.strip()
3068 if line.startswith('set noparent'):
3069 found_set_noparent_lines[''] = lineno
3070 if line.startswith('file://'):
3071 if line in allowed_owners_files:
3072 found_owners_files.add('')
3073 if line.startswith('per-file'):
3074 match = per_file_pattern.match(line)
3075 if match:
3076 glob = match.group(1).strip()
3077 directive = match.group(2).strip()
3078 if directive == 'set noparent':
3079 found_set_noparent_lines[glob] = lineno
3080 if directive.startswith('file://'):
3081 if directive in allowed_owners_files:
3082 found_owners_files.add(glob)
3083
3084 # Check that every set noparent line has a corresponding file:// line
3085 # listed in build/OWNERS.setnoparent. An exception is made for top level
3086 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493087 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3088 if (linux_path.count('/') != 1
3089 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503090 for set_noparent_line in found_set_noparent_lines:
3091 if set_noparent_line in found_owners_files:
3092 continue
3093 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493094 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503095 found_set_noparent_lines[set_noparent_line]))
3096
3097 results = []
3098 if errors:
3099 if input_api.is_committing:
3100 output = output_api.PresubmitError
3101 else:
3102 output = output_api.PresubmitPromptWarning
3103 results.append(
3104 output(
3105 'Found the following "set noparent" restrictions in OWNERS files that '
3106 'do not include owners from build/OWNERS.setnoparent:',
3107 long_text='\n\n'.join(errors)))
3108 return results
3109
3110
3111def CheckUselessForwardDeclarations(input_api, output_api):
3112 """Checks that added or removed lines in non third party affected
3113 header files do not lead to new useless class or struct forward
3114 declaration.
3115 """
3116 results = []
3117 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3118 input_api.re.MULTILINE)
3119 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3120 input_api.re.MULTILINE)
3121 for f in input_api.AffectedFiles(include_deletes=False):
3122 if (f.LocalPath().startswith('third_party')
3123 and not f.LocalPath().startswith('third_party/blink')
3124 and not f.LocalPath().startswith('third_party\\blink')):
3125 continue
3126
3127 if not f.LocalPath().endswith('.h'):
3128 continue
3129
3130 contents = input_api.ReadFile(f)
3131 fwd_decls = input_api.re.findall(class_pattern, contents)
3132 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3133
3134 useless_fwd_decls = []
3135 for decl in fwd_decls:
3136 count = sum(1 for _ in input_api.re.finditer(
3137 r'\b%s\b' % input_api.re.escape(decl), contents))
3138 if count == 1:
3139 useless_fwd_decls.append(decl)
3140
3141 if not useless_fwd_decls:
3142 continue
3143
3144 for line in f.GenerateScmDiff().splitlines():
3145 if (line.startswith('-') and not line.startswith('--')
3146 or line.startswith('+') and not line.startswith('++')):
3147 for decl in useless_fwd_decls:
3148 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3149 results.append(
3150 output_api.PresubmitPromptWarning(
3151 '%s: %s forward declaration is no longer needed'
3152 % (f.LocalPath(), decl)))
3153 useless_fwd_decls.remove(decl)
3154
3155 return results
3156
3157
3158def _CheckAndroidDebuggableBuild(input_api, output_api):
3159 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3160 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3161 this is a debuggable build of Android.
3162 """
3163 build_type_check_pattern = input_api.re.compile(
3164 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3165
3166 errors = []
3167
3168 sources = lambda affected_file: input_api.FilterSourceFile(
3169 affected_file,
3170 files_to_skip=(
3171 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3172 DEFAULT_FILES_TO_SKIP + (
3173 r"^android_webview[\\/]support_library[\\/]"
3174 "boundary_interfaces[\\/]",
3175 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3176 r'^third_party[\\/].*',
3177 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3178 r"webview[\\/]chromium[\\/]License.*",
3179 )),
3180 files_to_check=[r'.*\.java$'])
3181
3182 for f in input_api.AffectedSourceFiles(sources):
3183 for line_num, line in f.ChangedContents():
3184 if build_type_check_pattern.search(line):
3185 errors.append("%s:%d" % (f.LocalPath(), line_num))
3186
3187 results = []
3188
3189 if errors:
3190 results.append(
3191 output_api.PresubmitPromptWarning(
3192 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3193 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3194
3195 return results
3196
3197# TODO: add unit tests
3198def _CheckAndroidToastUsage(input_api, output_api):
3199 """Checks that code uses org.chromium.ui.widget.Toast instead of
3200 android.widget.Toast (Chromium Toast doesn't force hardware
3201 acceleration on low-end devices, saving memory).
3202 """
3203 toast_import_pattern = input_api.re.compile(
3204 r'^import android\.widget\.Toast;$')
3205
3206 errors = []
3207
3208 sources = lambda affected_file: input_api.FilterSourceFile(
3209 affected_file,
3210 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3211 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3212 r'^remoting[\\/].*')),
3213 files_to_check=[r'.*\.java$'])
3214
3215 for f in input_api.AffectedSourceFiles(sources):
3216 for line_num, line in f.ChangedContents():
3217 if toast_import_pattern.search(line):
3218 errors.append("%s:%d" % (f.LocalPath(), line_num))
3219
3220 results = []
3221
3222 if errors:
3223 results.append(
3224 output_api.PresubmitError(
3225 'android.widget.Toast usage is detected. Android toasts use hardware'
3226 ' acceleration, and can be\ncostly on low-end devices. Please use'
3227 ' org.chromium.ui.widget.Toast instead.\n'
3228 'Contact [email protected] if you have any questions.',
3229 errors))
3230
3231 return results
3232
3233
3234def _CheckAndroidCrLogUsage(input_api, output_api):
3235 """Checks that new logs using org.chromium.base.Log:
3236 - Are using 'TAG' as variable name for the tags (warn)
3237 - Are using a tag that is shorter than 20 characters (error)
3238 """
3239
3240 # Do not check format of logs in the given files
3241 cr_log_check_excluded_paths = [
3242 # //chrome/android/webapk cannot depend on //base
3243 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3244 # WebView license viewer code cannot depend on //base; used in stub APK.
3245 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3246 r"webview[\\/]chromium[\\/]License.*",
3247 # The customtabs_benchmark is a small app that does not depend on Chromium
3248 # java pieces.
3249 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3250 ]
3251
3252 cr_log_import_pattern = input_api.re.compile(
3253 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3254 class_in_base_pattern = input_api.re.compile(
3255 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3256 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3257 input_api.re.MULTILINE)
3258 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3259 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3260 log_decl_pattern = input_api.re.compile(
3261 r'static final String TAG = "(?P<name>(.*))"')
3262 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3263
3264 REF_MSG = ('See docs/android_logging.md for more info.')
3265 sources = lambda x: input_api.FilterSourceFile(
3266 x,
3267 files_to_check=[r'.*\.java$'],
3268 files_to_skip=cr_log_check_excluded_paths)
3269
3270 tag_decl_errors = []
3271 tag_length_errors = []
3272 tag_errors = []
3273 tag_with_dot_errors = []
3274 util_log_errors = []
3275
3276 for f in input_api.AffectedSourceFiles(sources):
3277 file_content = input_api.ReadFile(f)
3278 has_modified_logs = False
3279 # Per line checks
3280 if (cr_log_import_pattern.search(file_content)
3281 or (class_in_base_pattern.search(file_content)
3282 and not has_some_log_import_pattern.search(file_content))):
3283 # Checks to run for files using cr log
3284 for line_num, line in f.ChangedContents():
3285 if rough_log_decl_pattern.search(line):
3286 has_modified_logs = True
3287
3288 # Check if the new line is doing some logging
3289 match = log_call_pattern.search(line)
3290 if match:
3291 has_modified_logs = True
3292
3293 # Make sure it uses "TAG"
3294 if not match.group('tag') == 'TAG':
3295 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3296 else:
3297 # Report non cr Log function calls in changed lines
3298 for line_num, line in f.ChangedContents():
3299 if log_call_pattern.search(line):
3300 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3301
3302 # Per file checks
3303 if has_modified_logs:
3304 # Make sure the tag is using the "cr" prefix and is not too long
3305 match = log_decl_pattern.search(file_content)
3306 tag_name = match.group('name') if match else None
3307 if not tag_name:
3308 tag_decl_errors.append(f.LocalPath())
3309 elif len(tag_name) > 20:
3310 tag_length_errors.append(f.LocalPath())
3311 elif '.' in tag_name:
3312 tag_with_dot_errors.append(f.LocalPath())
3313
3314 results = []
3315 if tag_decl_errors:
3316 results.append(
3317 output_api.PresubmitPromptWarning(
3318 'Please define your tags using the suggested format: .\n'
3319 '"private static final String TAG = "<package tag>".\n'
3320 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3321 tag_decl_errors))
3322
3323 if tag_length_errors:
3324 results.append(
3325 output_api.PresubmitError(
3326 'The tag length is restricted by the system to be at most '
3327 '20 characters.\n' + REF_MSG, tag_length_errors))
3328
3329 if tag_errors:
3330 results.append(
3331 output_api.PresubmitPromptWarning(
3332 'Please use a variable named "TAG" for your log tags.\n' +
3333 REF_MSG, tag_errors))
3334
3335 if util_log_errors:
3336 results.append(
3337 output_api.PresubmitPromptWarning(
3338 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3339 util_log_errors))
3340
3341 if tag_with_dot_errors:
3342 results.append(
3343 output_api.PresubmitPromptWarning(
3344 'Dot in log tags cause them to be elided in crash reports.\n' +
3345 REF_MSG, tag_with_dot_errors))
3346
3347 return results
3348
3349
3350def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3351 """Checks that junit.framework.* is no longer used."""
3352 deprecated_junit_framework_pattern = input_api.re.compile(
3353 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3354 sources = lambda x: input_api.FilterSourceFile(
3355 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3356 errors = []
3357 for f in input_api.AffectedFiles(file_filter=sources):
3358 for line_num, line in f.ChangedContents():
3359 if deprecated_junit_framework_pattern.search(line):
3360 errors.append("%s:%d" % (f.LocalPath(), line_num))
3361
3362 results = []
3363 if errors:
3364 results.append(
3365 output_api.PresubmitError(
3366 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3367 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3368 ' if you have any question.', errors))
3369 return results
3370
3371
3372def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3373 """Checks that if new Java test classes have inheritance.
3374 Either the new test class is JUnit3 test or it is a JUnit4 test class
3375 with a base class, either case is undesirable.
3376 """
3377 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3378
3379 sources = lambda x: input_api.FilterSourceFile(
3380 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3381 errors = []
3382 for f in input_api.AffectedFiles(file_filter=sources):
3383 if not f.OldContents():
3384 class_declaration_start_flag = False
3385 for line_num, line in f.ChangedContents():
3386 if class_declaration_pattern.search(line):
3387 class_declaration_start_flag = True
3388 if class_declaration_start_flag and ' extends ' in line:
3389 errors.append('%s:%d' % (f.LocalPath(), line_num))
3390 if '{' in line:
3391 class_declaration_start_flag = False
3392
3393 results = []
3394 if errors:
3395 results.append(
3396 output_api.PresubmitPromptWarning(
3397 'The newly created files include Test classes that inherits from base'
3398 ' class. Please do not use inheritance in JUnit4 tests or add new'
3399 ' JUnit3 tests. Contact [email protected] if you have any'
3400 ' questions.', errors))
3401 return results
3402
3403
3404def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3405 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3406 deprecated_annotation_import_pattern = input_api.re.compile(
3407 r'^import android\.test\.suitebuilder\.annotation\..*;',
3408 input_api.re.MULTILINE)
3409 sources = lambda x: input_api.FilterSourceFile(
3410 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3411 errors = []
3412 for f in input_api.AffectedFiles(file_filter=sources):
3413 for line_num, line in f.ChangedContents():
3414 if deprecated_annotation_import_pattern.search(line):
3415 errors.append("%s:%d" % (f.LocalPath(), line_num))
3416
3417 results = []
3418 if errors:
3419 results.append(
3420 output_api.PresubmitError(
3421 'Annotations in android.test.suitebuilder.annotation have been'
3422 ' deprecated since API level 24. Please use android.support.test.filters'
3423 ' from //third_party/android_support_test_runner:runner_java instead.'
3424 ' Contact [email protected] if you have any questions.',
3425 errors))
3426 return results
3427
3428
3429def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3430 """Checks if MDPI assets are placed in a correct directory."""
3431 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3432 ('/res/drawable/' in f.LocalPath() or
3433 '/res/drawable-ldrtl/' in f.LocalPath()))
3434 errors = []
3435 for f in input_api.AffectedFiles(include_deletes=False,
3436 file_filter=file_filter):
3437 errors.append(' %s' % f.LocalPath())
3438
3439 results = []
3440 if errors:
3441 results.append(
3442 output_api.PresubmitError(
3443 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3444 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3445 '/res/drawable-ldrtl/.\n'
3446 'Contact [email protected] if you have questions.', errors))
3447 return results
3448
3449
3450def _CheckAndroidWebkitImports(input_api, output_api):
3451 """Checks that code uses org.chromium.base.Callback instead of
3452 android.webview.ValueCallback except in the WebView glue layer
3453 and WebLayer.
3454 """
3455 valuecallback_import_pattern = input_api.re.compile(
3456 r'^import android\.webkit\.ValueCallback;$')
3457
3458 errors = []
3459
3460 sources = lambda affected_file: input_api.FilterSourceFile(
3461 affected_file,
3462 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3463 DEFAULT_FILES_TO_SKIP + (
3464 r'^android_webview[\\/]glue[\\/].*',
3465 r'^weblayer[\\/].*',
3466 )),
3467 files_to_check=[r'.*\.java$'])
3468
3469 for f in input_api.AffectedSourceFiles(sources):
3470 for line_num, line in f.ChangedContents():
3471 if valuecallback_import_pattern.search(line):
3472 errors.append("%s:%d" % (f.LocalPath(), line_num))
3473
3474 results = []
3475
3476 if errors:
3477 results.append(
3478 output_api.PresubmitError(
3479 'android.webkit.ValueCallback usage is detected outside of the glue'
3480 ' layer. To stay compatible with the support library, android.webkit.*'
3481 ' classes should only be used inside the glue layer and'
3482 ' org.chromium.base.Callback should be used instead.', errors))
3483
3484 return results
3485
3486
3487def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3488 """Checks Android XML styles """
3489
3490 # Return early if no relevant files were modified.
3491 if not any(
3492 _IsXmlOrGrdFile(input_api, f.LocalPath())
3493 for f in input_api.AffectedFiles(include_deletes=False)):
3494 return []
3495
3496 import sys
3497 original_sys_path = sys.path
3498 try:
3499 sys.path = sys.path + [
3500 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3501 'android', 'checkxmlstyle')
3502 ]
3503 import checkxmlstyle
3504 finally:
3505 # Restore sys.path to what it was before.
3506 sys.path = original_sys_path
3507
3508 if is_check_on_upload:
3509 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3510 else:
3511 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3512
3513
3514def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3515 """Checks Android Infobar Deprecation """
3516
3517 import sys
3518 original_sys_path = sys.path
3519 try:
3520 sys.path = sys.path + [
3521 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3522 'android', 'infobar_deprecation')
3523 ]
3524 import infobar_deprecation
3525 finally:
3526 # Restore sys.path to what it was before.
3527 sys.path = original_sys_path
3528
3529 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3530
3531
3532class _PydepsCheckerResult:
3533 def __init__(self, cmd, pydeps_path, process, old_contents):
3534 self._cmd = cmd
3535 self._pydeps_path = pydeps_path
3536 self._process = process
3537 self._old_contents = old_contents
3538
3539 def GetError(self):
3540 """Returns an error message, or None."""
3541 import difflib
3542 if self._process.wait() != 0:
3543 # STDERR should already be printed.
3544 return 'Command failed: ' + self._cmd
3545 new_contents = self._process.stdout.read().splitlines()[2:]
3546 if self._old_contents != new_contents:
3547 diff = '\n'.join(
3548 difflib.context_diff(self._old_contents, new_contents))
3549 return ('File is stale: {}\n'
3550 'Diff (apply to fix):\n'
3551 '{}\n'
3552 'To regenerate, run:\n\n'
3553 ' {}').format(self._pydeps_path, diff, self._cmd)
3554 return None
3555
3556
3557class PydepsChecker:
3558 def __init__(self, input_api, pydeps_files):
3559 self._file_cache = {}
3560 self._input_api = input_api
3561 self._pydeps_files = pydeps_files
3562
3563 def _LoadFile(self, path):
3564 """Returns the list of paths within a .pydeps file relative to //."""
3565 if path not in self._file_cache:
3566 with open(path, encoding='utf-8') as f:
3567 self._file_cache[path] = f.read()
3568 return self._file_cache[path]
3569
3570 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3571 """Returns an interable of paths within the .pydep, relativized to //."""
3572 pydeps_data = self._LoadFile(pydeps_path)
3573 uses_gn_paths = '--gn-paths' in pydeps_data
3574 entries = (l for l in pydeps_data.splitlines()
3575 if not l.startswith('#'))
3576 if uses_gn_paths:
3577 # Paths look like: //foo/bar/baz
3578 return (e[2:] for e in entries)
3579 else:
3580 # Paths look like: path/relative/to/file.pydeps
3581 os_path = self._input_api.os_path
3582 pydeps_dir = os_path.dirname(pydeps_path)
3583 return (os_path.normpath(os_path.join(pydeps_dir, e))
3584 for e in entries)
3585
3586 def _CreateFilesToPydepsMap(self):
3587 """Returns a map of local_path -> list_of_pydeps."""
3588 ret = {}
3589 for pydep_local_path in self._pydeps_files:
3590 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3591 ret.setdefault(path, []).append(pydep_local_path)
3592 return ret
3593
3594 def ComputeAffectedPydeps(self):
3595 """Returns an iterable of .pydeps files that might need regenerating."""
3596 affected_pydeps = set()
3597 file_to_pydeps_map = None
3598 for f in self._input_api.AffectedFiles(include_deletes=True):
3599 local_path = f.LocalPath()
3600 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3601 # subrepositories. We can't figure out which files change, so re-check
3602 # all files.
3603 # Changes to print_python_deps.py affect all .pydeps.
3604 if local_path in ('DEPS', 'PRESUBMIT.py'
3605 ) or local_path.endswith('print_python_deps.py'):
3606 return self._pydeps_files
3607 elif local_path.endswith('.pydeps'):
3608 if local_path in self._pydeps_files:
3609 affected_pydeps.add(local_path)
3610 elif local_path.endswith('.py'):
3611 if file_to_pydeps_map is None:
3612 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3613 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3614 return affected_pydeps
3615
3616 def DetermineIfStaleAsync(self, pydeps_path):
3617 """Runs print_python_deps.py to see if the files is stale."""
3618 import os
3619
3620 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3621 if old_pydeps_data:
3622 cmd = old_pydeps_data[1][1:].strip()
3623 if '--output' not in cmd:
3624 cmd += ' --output ' + pydeps_path
3625 old_contents = old_pydeps_data[2:]
3626 else:
3627 # A default cmd that should work in most cases (as long as pydeps filename
3628 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3629 # file is empty/new.
3630 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3631 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3632 old_contents = []
3633 env = dict(os.environ)
3634 env['PYTHONDONTWRITEBYTECODE'] = '1'
3635 process = self._input_api.subprocess.Popen(
3636 cmd + ' --output ""',
3637 shell=True,
3638 env=env,
3639 stdout=self._input_api.subprocess.PIPE,
3640 encoding='utf-8')
3641 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403642
3643
Tibor Goldschwendt360793f72019-06-25 18:23:493644def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503645 args = {}
3646 with open('build/config/gclient_args.gni', 'r') as f:
3647 for line in f:
3648 line = line.strip()
3649 if not line or line.startswith('#'):
3650 continue
3651 attribute, value = line.split('=')
3652 args[attribute.strip()] = value.strip()
3653 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493654
3655
Saagar Sanghavifceeaae2020-08-12 16:40:363656def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503657 """Checks if a .pydeps file needs to be regenerated."""
3658 # This check is for Python dependency lists (.pydeps files), and involves
3659 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3660 # doesn't work on Windows and Mac, so skip it on other platforms.
3661 if not input_api.platform.startswith('linux'):
3662 return []
Erik Staabc734cd7a2021-11-23 03:11:523663
Sam Maiera6e76d72022-02-11 21:43:503664 results = []
3665 # First, check for new / deleted .pydeps.
3666 for f in input_api.AffectedFiles(include_deletes=True):
3667 # Check whether we are running the presubmit check for a file in src.
3668 # f.LocalPath is relative to repo (src, or internal repo).
3669 # os_path.exists is relative to src repo.
3670 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3671 # to src and we can conclude that the pydeps is in src.
3672 if f.LocalPath().endswith('.pydeps'):
3673 if input_api.os_path.exists(f.LocalPath()):
3674 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3675 results.append(
3676 output_api.PresubmitError(
3677 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3678 'remove %s' % f.LocalPath()))
3679 elif f.Action() != 'D' and f.LocalPath(
3680 ) not in _ALL_PYDEPS_FILES:
3681 results.append(
3682 output_api.PresubmitError(
3683 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3684 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403685
Sam Maiera6e76d72022-02-11 21:43:503686 if results:
3687 return results
3688
3689 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3690 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3691 affected_pydeps = set(checker.ComputeAffectedPydeps())
3692 affected_android_pydeps = affected_pydeps.intersection(
3693 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3694 if affected_android_pydeps and not is_android:
3695 results.append(
3696 output_api.PresubmitPromptOrNotify(
3697 'You have changed python files that may affect pydeps for android\n'
3698 'specific scripts. However, the relevant presumbit check cannot be\n'
3699 'run because you are not using an Android checkout. To validate that\n'
3700 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3701 'use the android-internal-presubmit optional trybot.\n'
3702 'Possibly stale pydeps files:\n{}'.format(
3703 '\n'.join(affected_android_pydeps))))
3704
3705 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3706 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3707 # Process these concurrently, as each one takes 1-2 seconds.
3708 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3709 for result in pydep_results:
3710 error_msg = result.GetError()
3711 if error_msg:
3712 results.append(output_api.PresubmitError(error_msg))
3713
agrievef32bcc72016-04-04 14:57:403714 return results
3715
agrievef32bcc72016-04-04 14:57:403716
Saagar Sanghavifceeaae2020-08-12 16:40:363717def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503718 """Checks to make sure no header files have |Singleton<|."""
3719
3720 def FileFilter(affected_file):
3721 # It's ok for base/memory/singleton.h to have |Singleton<|.
3722 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3723 (r"^base[\\/]memory[\\/]singleton\.h$",
3724 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443725 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503726 return input_api.FilterSourceFile(affected_file,
3727 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433728
Sam Maiera6e76d72022-02-11 21:43:503729 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3730 files = []
3731 for f in input_api.AffectedSourceFiles(FileFilter):
3732 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3733 or f.LocalPath().endswith('.hpp')
3734 or f.LocalPath().endswith('.inl')):
3735 contents = input_api.ReadFile(f)
3736 for line in contents.splitlines(False):
3737 if (not line.lstrip().startswith('//')
3738 and # Strip C++ comment.
3739 pattern.search(line)):
3740 files.append(f)
3741 break
glidere61efad2015-02-18 17:39:433742
Sam Maiera6e76d72022-02-11 21:43:503743 if files:
3744 return [
3745 output_api.PresubmitError(
3746 'Found base::Singleton<T> in the following header files.\n' +
3747 'Please move them to an appropriate source file so that the ' +
3748 'template gets instantiated in a single compilation unit.',
3749 files)
3750 ]
3751 return []
glidere61efad2015-02-18 17:39:433752
3753
[email protected]fd20b902014-05-09 02:14:533754_DEPRECATED_CSS = [
3755 # Values
3756 ( "-webkit-box", "flex" ),
3757 ( "-webkit-inline-box", "inline-flex" ),
3758 ( "-webkit-flex", "flex" ),
3759 ( "-webkit-inline-flex", "inline-flex" ),
3760 ( "-webkit-min-content", "min-content" ),
3761 ( "-webkit-max-content", "max-content" ),
3762
3763 # Properties
3764 ( "-webkit-background-clip", "background-clip" ),
3765 ( "-webkit-background-origin", "background-origin" ),
3766 ( "-webkit-background-size", "background-size" ),
3767 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443768 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533769
3770 # Functions
3771 ( "-webkit-gradient", "gradient" ),
3772 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3773 ( "-webkit-linear-gradient", "linear-gradient" ),
3774 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3775 ( "-webkit-radial-gradient", "radial-gradient" ),
3776 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3777]
3778
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203779
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493780# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363781def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503782 """ Make sure that we don't use deprecated CSS
3783 properties, functions or values. Our external
3784 documentation and iOS CSS for dom distiller
3785 (reader mode) are ignored by the hooks as it
3786 needs to be consumed by WebKit. """
3787 results = []
3788 file_inclusion_pattern = [r".+\.css$"]
3789 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3790 input_api.DEFAULT_FILES_TO_SKIP +
3791 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3792 r"^native_client_sdk"))
3793 file_filter = lambda f: input_api.FilterSourceFile(
3794 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3795 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3796 for line_num, line in fpath.ChangedContents():
3797 for (deprecated_value, value) in _DEPRECATED_CSS:
3798 if deprecated_value in line:
3799 results.append(
3800 output_api.PresubmitError(
3801 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3802 (fpath.LocalPath(), line_num, deprecated_value,
3803 value)))
3804 return results
[email protected]fd20b902014-05-09 02:14:533805
mohan.reddyf21db962014-10-16 12:26:473806
Saagar Sanghavifceeaae2020-08-12 16:40:363807def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503808 bad_files = {}
3809 for f in input_api.AffectedFiles(include_deletes=False):
3810 if (f.LocalPath().startswith('third_party')
3811 and not f.LocalPath().startswith('third_party/blink')
3812 and not f.LocalPath().startswith('third_party\\blink')):
3813 continue
rlanday6802cf632017-05-30 17:48:363814
Sam Maiera6e76d72022-02-11 21:43:503815 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3816 continue
rlanday6802cf632017-05-30 17:48:363817
Sam Maiera6e76d72022-02-11 21:43:503818 relative_includes = [
3819 line for _, line in f.ChangedContents()
3820 if "#include" in line and "../" in line
3821 ]
3822 if not relative_includes:
3823 continue
3824 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363825
Sam Maiera6e76d72022-02-11 21:43:503826 if not bad_files:
3827 return []
rlanday6802cf632017-05-30 17:48:363828
Sam Maiera6e76d72022-02-11 21:43:503829 error_descriptions = []
3830 for file_path, bad_lines in bad_files.items():
3831 error_description = file_path
3832 for line in bad_lines:
3833 error_description += '\n ' + line
3834 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363835
Sam Maiera6e76d72022-02-11 21:43:503836 results = []
3837 results.append(
3838 output_api.PresubmitError(
3839 'You added one or more relative #include paths (including "../").\n'
3840 'These shouldn\'t be used because they can be used to include headers\n'
3841 'from code that\'s not correctly specified as a dependency in the\n'
3842 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363843
Sam Maiera6e76d72022-02-11 21:43:503844 return results
rlanday6802cf632017-05-30 17:48:363845
Takeshi Yoshinoe387aa32017-08-02 13:16:133846
Saagar Sanghavifceeaae2020-08-12 16:40:363847def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503848 """Check that nobody tries to include a cc file. It's a relatively
3849 common error which results in duplicate symbols in object
3850 files. This may not always break the build until someone later gets
3851 very confusing linking errors."""
3852 results = []
3853 for f in input_api.AffectedFiles(include_deletes=False):
3854 # We let third_party code do whatever it wants
3855 if (f.LocalPath().startswith('third_party')
3856 and not f.LocalPath().startswith('third_party/blink')
3857 and not f.LocalPath().startswith('third_party\\blink')):
3858 continue
Daniel Bratell65b033262019-04-23 08:17:063859
Sam Maiera6e76d72022-02-11 21:43:503860 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3861 continue
Daniel Bratell65b033262019-04-23 08:17:063862
Sam Maiera6e76d72022-02-11 21:43:503863 for _, line in f.ChangedContents():
3864 if line.startswith('#include "'):
3865 included_file = line.split('"')[1]
3866 if _IsCPlusPlusFile(input_api, included_file):
3867 # The most common naming for external files with C++ code,
3868 # apart from standard headers, is to call them foo.inc, but
3869 # Chromium sometimes uses foo-inc.cc so allow that as well.
3870 if not included_file.endswith(('.h', '-inc.cc')):
3871 results.append(
3872 output_api.PresubmitError(
3873 'Only header files or .inc files should be included in other\n'
3874 'C++ files. Compiling the contents of a cc file more than once\n'
3875 'will cause duplicate information in the build which may later\n'
3876 'result in strange link_errors.\n' +
3877 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063878
Sam Maiera6e76d72022-02-11 21:43:503879 return results
Daniel Bratell65b033262019-04-23 08:17:063880
3881
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203882def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503883 if not isinstance(key, ast.Str):
3884 return 'Key at line %d must be a string literal' % key.lineno
3885 if not isinstance(value, ast.Dict):
3886 return 'Value at line %d must be a dict' % value.lineno
3887 if len(value.keys) != 1:
3888 return 'Dict at line %d must have single entry' % value.lineno
3889 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3890 return (
3891 'Entry at line %d must have a string literal \'filepath\' as key' %
3892 value.lineno)
3893 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133894
Takeshi Yoshinoe387aa32017-08-02 13:16:133895
Sergey Ulanov4af16052018-11-08 02:41:463896def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503897 if not isinstance(key, ast.Str):
3898 return 'Key at line %d must be a string literal' % key.lineno
3899 if not isinstance(value, ast.List):
3900 return 'Value at line %d must be a list' % value.lineno
3901 for element in value.elts:
3902 if not isinstance(element, ast.Str):
3903 return 'Watchlist elements on line %d is not a string' % key.lineno
3904 if not email_regex.match(element.s):
3905 return ('Watchlist element on line %d doesn\'t look like a valid '
3906 + 'email: %s') % (key.lineno, element.s)
3907 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133908
Takeshi Yoshinoe387aa32017-08-02 13:16:133909
Sergey Ulanov4af16052018-11-08 02:41:463910def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:503911 mismatch_template = (
3912 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3913 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133914
Sam Maiera6e76d72022-02-11 21:43:503915 email_regex = input_api.re.compile(
3916 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:463917
Sam Maiera6e76d72022-02-11 21:43:503918 ast = input_api.ast
3919 i = 0
3920 last_key = ''
3921 while True:
3922 if i >= len(wd_dict.keys):
3923 if i >= len(w_dict.keys):
3924 return None
3925 return mismatch_template % ('missing',
3926 'line %d' % w_dict.keys[i].lineno)
3927 elif i >= len(w_dict.keys):
3928 return (mismatch_template %
3929 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133930
Sam Maiera6e76d72022-02-11 21:43:503931 wd_key = wd_dict.keys[i]
3932 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133933
Sam Maiera6e76d72022-02-11 21:43:503934 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
3935 wd_dict.values[i], ast)
3936 if result is not None:
3937 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133938
Sam Maiera6e76d72022-02-11 21:43:503939 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
3940 email_regex)
3941 if result is not None:
3942 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203943
Sam Maiera6e76d72022-02-11 21:43:503944 if wd_key.s != w_key.s:
3945 return mismatch_template % ('%s at line %d' %
3946 (wd_key.s, wd_key.lineno),
3947 '%s at line %d' %
3948 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203949
Sam Maiera6e76d72022-02-11 21:43:503950 if wd_key.s < last_key:
3951 return (
3952 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
3953 % (wd_key.lineno, w_key.lineno))
3954 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203955
Sam Maiera6e76d72022-02-11 21:43:503956 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203957
3958
Sergey Ulanov4af16052018-11-08 02:41:463959def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:503960 ast = input_api.ast
3961 if not isinstance(expression, ast.Expression):
3962 return 'WATCHLISTS file must contain a valid expression'
3963 dictionary = expression.body
3964 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3965 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203966
Sam Maiera6e76d72022-02-11 21:43:503967 first_key = dictionary.keys[0]
3968 first_value = dictionary.values[0]
3969 second_key = dictionary.keys[1]
3970 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203971
Sam Maiera6e76d72022-02-11 21:43:503972 if (not isinstance(first_key, ast.Str)
3973 or first_key.s != 'WATCHLIST_DEFINITIONS'
3974 or not isinstance(first_value, ast.Dict)):
3975 return ('The first entry of the dict in WATCHLISTS file must be '
3976 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203977
Sam Maiera6e76d72022-02-11 21:43:503978 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
3979 or not isinstance(second_value, ast.Dict)):
3980 return ('The second entry of the dict in WATCHLISTS file must be '
3981 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203982
Sam Maiera6e76d72022-02-11 21:43:503983 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
3985
Saagar Sanghavifceeaae2020-08-12 16:40:363986def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503987 for f in input_api.AffectedFiles(include_deletes=False):
3988 if f.LocalPath() == 'WATCHLISTS':
3989 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:133990
Sam Maiera6e76d72022-02-11 21:43:503991 try:
3992 # First, make sure that it can be evaluated.
3993 input_api.ast.literal_eval(contents)
3994 # Get an AST tree for it and scan the tree for detailed style checking.
3995 expression = input_api.ast.parse(contents,
3996 filename='WATCHLISTS',
3997 mode='eval')
3998 except ValueError as e:
3999 return [
4000 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4001 long_text=repr(e))
4002 ]
4003 except SyntaxError as e:
4004 return [
4005 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4006 long_text=repr(e))
4007 ]
4008 except TypeError as e:
4009 return [
4010 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4011 long_text=repr(e))
4012 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134013
Sam Maiera6e76d72022-02-11 21:43:504014 result = _CheckWATCHLISTSSyntax(expression, input_api)
4015 if result is not None:
4016 return [output_api.PresubmitError(result)]
4017 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134018
Sam Maiera6e76d72022-02-11 21:43:504019 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134020
4021
Andrew Grieve1b290e4a22020-11-24 20:07:014022def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504023 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014024
Sam Maiera6e76d72022-02-11 21:43:504025 As documented at //build/docs/writing_gn_templates.md
4026 """
Andrew Grieve1b290e4a22020-11-24 20:07:014027
Sam Maiera6e76d72022-02-11 21:43:504028 def gn_files(f):
4029 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014030
Sam Maiera6e76d72022-02-11 21:43:504031 problems = []
4032 for f in input_api.AffectedSourceFiles(gn_files):
4033 for line_num, line in f.ChangedContents():
4034 if 'forward_variables_from(invoker, "*")' in line:
4035 problems.append(
4036 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4037 (f.LocalPath(), line_num))
4038
4039 if problems:
4040 return [
4041 output_api.PresubmitPromptWarning(
4042 'forward_variables_from("*") without exclusions',
4043 items=sorted(problems),
4044 long_text=(
4045 'The variables "visibilty" and "test_only" should be '
4046 'explicitly listed in forward_variables_from(). For more '
4047 'details, see:\n'
4048 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4049 'build/docs/writing_gn_templates.md'
4050 '#Using-forward_variables_from'))
4051 ]
4052 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014053
4054
Saagar Sanghavifceeaae2020-08-12 16:40:364055def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504056 """Checks that newly added header files have corresponding GN changes.
4057 Note that this is only a heuristic. To be precise, run script:
4058 build/check_gn_headers.py.
4059 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194060
Sam Maiera6e76d72022-02-11 21:43:504061 def headers(f):
4062 return input_api.FilterSourceFile(
4063 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194064
Sam Maiera6e76d72022-02-11 21:43:504065 new_headers = []
4066 for f in input_api.AffectedSourceFiles(headers):
4067 if f.Action() != 'A':
4068 continue
4069 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194070
Sam Maiera6e76d72022-02-11 21:43:504071 def gn_files(f):
4072 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194073
Sam Maiera6e76d72022-02-11 21:43:504074 all_gn_changed_contents = ''
4075 for f in input_api.AffectedSourceFiles(gn_files):
4076 for _, line in f.ChangedContents():
4077 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194078
Sam Maiera6e76d72022-02-11 21:43:504079 problems = []
4080 for header in new_headers:
4081 basename = input_api.os_path.basename(header)
4082 if basename not in all_gn_changed_contents:
4083 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194084
Sam Maiera6e76d72022-02-11 21:43:504085 if problems:
4086 return [
4087 output_api.PresubmitPromptWarning(
4088 'Missing GN changes for new header files',
4089 items=sorted(problems),
4090 long_text=
4091 'Please double check whether newly added header files need '
4092 'corresponding changes in gn or gni files.\nThis checking is only a '
4093 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4094 'Read https://crbug.com/661774 for more info.')
4095 ]
4096 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194097
4098
Saagar Sanghavifceeaae2020-08-12 16:40:364099def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504100 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024101
Sam Maiera6e76d72022-02-11 21:43:504102 This assumes we won't intentionally reference one product from the other
4103 product.
4104 """
4105 all_problems = []
4106 test_cases = [{
4107 "filename_postfix": "google_chrome_strings.grd",
4108 "correct_name": "Chrome",
4109 "incorrect_name": "Chromium",
4110 }, {
4111 "filename_postfix": "chromium_strings.grd",
4112 "correct_name": "Chromium",
4113 "incorrect_name": "Chrome",
4114 }]
Michael Giuffridad3bc8672018-10-25 22:48:024115
Sam Maiera6e76d72022-02-11 21:43:504116 for test_case in test_cases:
4117 problems = []
4118 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4119 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024120
Sam Maiera6e76d72022-02-11 21:43:504121 # Check each new line. Can yield false positives in multiline comments, but
4122 # easier than trying to parse the XML because messages can have nested
4123 # children, and associating message elements with affected lines is hard.
4124 for f in input_api.AffectedSourceFiles(filename_filter):
4125 for line_num, line in f.ChangedContents():
4126 if "<message" in line or "<!--" in line or "-->" in line:
4127 continue
4128 if test_case["incorrect_name"] in line:
4129 problems.append("Incorrect product name in %s:%d" %
4130 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024131
Sam Maiera6e76d72022-02-11 21:43:504132 if problems:
4133 message = (
4134 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4135 % (test_case["correct_name"], test_case["correct_name"],
4136 test_case["incorrect_name"]))
4137 all_problems.append(
4138 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024139
Sam Maiera6e76d72022-02-11 21:43:504140 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024141
4142
Saagar Sanghavifceeaae2020-08-12 16:40:364143def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504144 """Avoid large files, especially binary files, in the repository since
4145 git doesn't scale well for those. They will be in everyone's repo
4146 clones forever, forever making Chromium slower to clone and work
4147 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364148
Sam Maiera6e76d72022-02-11 21:43:504149 # Uploading files to cloud storage is not trivial so we don't want
4150 # to set the limit too low, but the upper limit for "normal" large
4151 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4152 # anything over 20 MB is exceptional.
4153 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364154
Sam Maiera6e76d72022-02-11 21:43:504155 too_large_files = []
4156 for f in input_api.AffectedFiles():
4157 # Check both added and modified files (but not deleted files).
4158 if f.Action() in ('A', 'M'):
4159 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4160 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4161 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364162
Sam Maiera6e76d72022-02-11 21:43:504163 if too_large_files:
4164 message = (
4165 'Do not commit large files to git since git scales badly for those.\n'
4166 +
4167 'Instead put the large files in cloud storage and use DEPS to\n' +
4168 'fetch them.\n' + '\n'.join(too_large_files))
4169 return [
4170 output_api.PresubmitError('Too large files found in commit',
4171 long_text=message + '\n')
4172 ]
4173 else:
4174 return []
Daniel Bratell93eb6c62019-04-29 20:13:364175
Max Morozb47503b2019-08-08 21:03:274176
Saagar Sanghavifceeaae2020-08-12 16:40:364177def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504178 """Checks specific for fuzz target sources."""
4179 EXPORTED_SYMBOLS = [
4180 'LLVMFuzzerInitialize',
4181 'LLVMFuzzerCustomMutator',
4182 'LLVMFuzzerCustomCrossOver',
4183 'LLVMFuzzerMutate',
4184 ]
Max Morozb47503b2019-08-08 21:03:274185
Sam Maiera6e76d72022-02-11 21:43:504186 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274187
Sam Maiera6e76d72022-02-11 21:43:504188 def FilterFile(affected_file):
4189 """Ignore libFuzzer source code."""
4190 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4191 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274192
Sam Maiera6e76d72022-02-11 21:43:504193 return input_api.FilterSourceFile(affected_file,
4194 files_to_check=[files_to_check],
4195 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274196
Sam Maiera6e76d72022-02-11 21:43:504197 files_with_missing_header = []
4198 for f in input_api.AffectedSourceFiles(FilterFile):
4199 contents = input_api.ReadFile(f, 'r')
4200 if REQUIRED_HEADER in contents:
4201 continue
Max Morozb47503b2019-08-08 21:03:274202
Sam Maiera6e76d72022-02-11 21:43:504203 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4204 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274205
Sam Maiera6e76d72022-02-11 21:43:504206 if not files_with_missing_header:
4207 return []
Max Morozb47503b2019-08-08 21:03:274208
Sam Maiera6e76d72022-02-11 21:43:504209 long_text = (
4210 'If you define any of the libFuzzer optional functions (%s), it is '
4211 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4212 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4213 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4214 'to access command line arguments passed to the fuzzer. Instead, prefer '
4215 'static initialization and shared resources as documented in '
4216 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4217 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4218 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274219
Sam Maiera6e76d72022-02-11 21:43:504220 return [
4221 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4222 REQUIRED_HEADER,
4223 items=files_with_missing_header,
4224 long_text=long_text)
4225 ]
Max Morozb47503b2019-08-08 21:03:274226
4227
Mohamed Heikald048240a2019-11-12 16:57:374228def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504229 """
4230 Warns authors who add images into the repo to make sure their images are
4231 optimized before committing.
4232 """
4233 images_added = False
4234 image_paths = []
4235 errors = []
4236 filter_lambda = lambda x: input_api.FilterSourceFile(
4237 x,
4238 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4239 DEFAULT_FILES_TO_SKIP),
4240 files_to_check=[r'.*\/(drawable|mipmap)'])
4241 for f in input_api.AffectedFiles(include_deletes=False,
4242 file_filter=filter_lambda):
4243 local_path = f.LocalPath().lower()
4244 if any(
4245 local_path.endswith(extension)
4246 for extension in _IMAGE_EXTENSIONS):
4247 images_added = True
4248 image_paths.append(f)
4249 if images_added:
4250 errors.append(
4251 output_api.PresubmitPromptWarning(
4252 'It looks like you are trying to commit some images. If these are '
4253 'non-test-only images, please make sure to read and apply the tips in '
4254 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4255 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4256 'FYI only and will not block your CL on the CQ.', image_paths))
4257 return errors
Mohamed Heikald048240a2019-11-12 16:57:374258
4259
Saagar Sanghavifceeaae2020-08-12 16:40:364260def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504261 """Groups upload checks that target android code."""
4262 results = []
4263 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4264 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4265 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4266 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4267 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4268 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4269 input_api, output_api))
4270 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4271 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4272 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4273 results.extend(_CheckNewImagesWarning(input_api, output_api))
4274 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4275 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4276 return results
4277
Becky Zhou7c69b50992018-12-10 19:37:574278
Saagar Sanghavifceeaae2020-08-12 16:40:364279def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504280 """Groups commit checks that target android code."""
4281 results = []
4282 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4283 return results
dgnaa68d5e2015-06-10 10:08:224284
Chris Hall59f8d0c72020-05-01 07:31:194285# TODO(chrishall): could we additionally match on any path owned by
4286# ui/accessibility/OWNERS ?
4287_ACCESSIBILITY_PATHS = (
4288 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4289 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4290 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4291 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4292 r"^content[\\/]browser[\\/]accessibility[\\/]",
4293 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4294 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4295 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4296 r"^ui[\\/]accessibility[\\/]",
4297 r"^ui[\\/]views[\\/]accessibility[\\/]",
4298)
4299
Saagar Sanghavifceeaae2020-08-12 16:40:364300def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504301 """Checks that commits to accessibility code contain an AX-Relnotes field in
4302 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194303
Sam Maiera6e76d72022-02-11 21:43:504304 def FileFilter(affected_file):
4305 paths = _ACCESSIBILITY_PATHS
4306 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194307
Sam Maiera6e76d72022-02-11 21:43:504308 # Only consider changes affecting accessibility paths.
4309 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4310 return []
Akihiro Ota08108e542020-05-20 15:30:534311
Sam Maiera6e76d72022-02-11 21:43:504312 # AX-Relnotes can appear in either the description or the footer.
4313 # When searching the description, require 'AX-Relnotes:' to appear at the
4314 # beginning of a line.
4315 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4316 description_has_relnotes = any(
4317 ax_regex.match(line)
4318 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194319
Sam Maiera6e76d72022-02-11 21:43:504320 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4321 'AX-Relnotes', [])
4322 if description_has_relnotes or footer_relnotes:
4323 return []
Chris Hall59f8d0c72020-05-01 07:31:194324
Sam Maiera6e76d72022-02-11 21:43:504325 # TODO(chrishall): link to Relnotes documentation in message.
4326 message = (
4327 "Missing 'AX-Relnotes:' field required for accessibility changes"
4328 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4329 "user-facing changes"
4330 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4331 "user-facing effects"
4332 "\n if this is confusing or annoying then please contact members "
4333 "of ui/accessibility/OWNERS.")
4334
4335 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224336
Mark Schillacie5a0be22022-01-19 00:38:394337
4338_ACCESSIBILITY_EVENTS_TEST_PATH = (
4339 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4340)
4341
4342_ACCESSIBILITY_TREE_TEST_PATH = (
4343 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4344 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4345 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4346 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4347)
4348
4349_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4350 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4351)
4352
4353_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444354 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394355)
4356
4357def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504358 """Checks that commits that include a newly added, renamed/moved, or deleted
4359 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4360 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394361
Sam Maiera6e76d72022-02-11 21:43:504362 def FilePathFilter(affected_file):
4363 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4364 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394365
Sam Maiera6e76d72022-02-11 21:43:504366 def AndroidFilePathFilter(affected_file):
4367 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4368 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394369
Sam Maiera6e76d72022-02-11 21:43:504370 # Only consider changes in the events test data path with html type.
4371 if not any(
4372 input_api.AffectedFiles(include_deletes=True,
4373 file_filter=FilePathFilter)):
4374 return []
Mark Schillacie5a0be22022-01-19 00:38:394375
Sam Maiera6e76d72022-02-11 21:43:504376 # If the commit contains any change to the Android test file, ignore.
4377 if any(
4378 input_api.AffectedFiles(include_deletes=True,
4379 file_filter=AndroidFilePathFilter)):
4380 return []
Mark Schillacie5a0be22022-01-19 00:38:394381
Sam Maiera6e76d72022-02-11 21:43:504382 # Only consider changes that are adding/renaming or deleting a file
4383 message = []
4384 for f in input_api.AffectedFiles(include_deletes=True,
4385 file_filter=FilePathFilter):
4386 if f.Action() == 'A' or f.Action() == 'D':
4387 message = (
4388 "It appears that you are adding, renaming or deleting"
4389 "\na dump_accessibility_events* test, but have not included"
4390 "\na corresponding change for Android."
4391 "\nPlease include (or remove) the test from:"
4392 "\n content/public/android/javatests/src/org/chromium/"
4393 "content/browser/accessibility/"
4394 "WebContentsAccessibilityEventsTest.java"
4395 "\nIf this message is confusing or annoying, please contact"
4396 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394397
Sam Maiera6e76d72022-02-11 21:43:504398 # If no message was set, return empty.
4399 if not len(message):
4400 return []
4401
4402 return [output_api.PresubmitPromptWarning(message)]
4403
Mark Schillacie5a0be22022-01-19 00:38:394404
4405def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504406 """Checks that commits that include a newly added, renamed/moved, or deleted
4407 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4408 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394409
Sam Maiera6e76d72022-02-11 21:43:504410 def FilePathFilter(affected_file):
4411 paths = _ACCESSIBILITY_TREE_TEST_PATH
4412 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394413
Sam Maiera6e76d72022-02-11 21:43:504414 def AndroidFilePathFilter(affected_file):
4415 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4416 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394417
Sam Maiera6e76d72022-02-11 21:43:504418 # Only consider changes in the various tree test data paths with html type.
4419 if not any(
4420 input_api.AffectedFiles(include_deletes=True,
4421 file_filter=FilePathFilter)):
4422 return []
Mark Schillacie5a0be22022-01-19 00:38:394423
Sam Maiera6e76d72022-02-11 21:43:504424 # If the commit contains any change to the Android test file, ignore.
4425 if any(
4426 input_api.AffectedFiles(include_deletes=True,
4427 file_filter=AndroidFilePathFilter)):
4428 return []
Mark Schillacie5a0be22022-01-19 00:38:394429
Sam Maiera6e76d72022-02-11 21:43:504430 # Only consider changes that are adding/renaming or deleting a file
4431 message = []
4432 for f in input_api.AffectedFiles(include_deletes=True,
4433 file_filter=FilePathFilter):
4434 if f.Action() == 'A' or f.Action() == 'D':
4435 message = (
4436 "It appears that you are adding, renaming or deleting"
4437 "\na dump_accessibility_tree* test, but have not included"
4438 "\na corresponding change for Android."
4439 "\nPlease include (or remove) the test from:"
4440 "\n content/public/android/javatests/src/org/chromium/"
4441 "content/browser/accessibility/"
4442 "WebContentsAccessibilityTreeTest.java"
4443 "\nIf this message is confusing or annoying, please contact"
4444 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394445
Sam Maiera6e76d72022-02-11 21:43:504446 # If no message was set, return empty.
4447 if not len(message):
4448 return []
4449
4450 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394451
4452
seanmccullough4a9356252021-04-08 19:54:094453# string pattern, sequence of strings to show when pattern matches,
4454# error flag. True if match is a presubmit error, otherwise it's a warning.
4455_NON_INCLUSIVE_TERMS = (
4456 (
4457 # Note that \b pattern in python re is pretty particular. In this
4458 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4459 # ...' will not. This may require some tweaking to catch these cases
4460 # without triggering a lot of false positives. Leaving it naive and
4461 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324462 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094463 (
4464 'Please don\'t use blacklist, whitelist, ' # nocheck
4465 'or slave in your', # nocheck
4466 'code and make every effort to use other terms. Using "// nocheck"',
4467 '"# nocheck" or "<!-- nocheck -->"',
4468 'at the end of the offending line will bypass this PRESUBMIT error',
4469 'but avoid using this whenever possible. Reach out to',
4470 '[email protected] if you have questions'),
4471 True),)
4472
Saagar Sanghavifceeaae2020-08-12 16:40:364473def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504474 """Checks common to both upload and commit."""
4475 results = []
Eric Boren6fd2b932018-01-25 15:05:084476 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504477 input_api.canned_checks.PanProjectChecks(
4478 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084479
Sam Maiera6e76d72022-02-11 21:43:504480 author = input_api.change.author_email
4481 if author and author not in _KNOWN_ROBOTS:
4482 results.extend(
4483 input_api.canned_checks.CheckAuthorizedAuthor(
4484 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244485
Sam Maiera6e76d72022-02-11 21:43:504486 results.extend(
4487 input_api.canned_checks.CheckChangeHasNoTabs(
4488 input_api,
4489 output_api,
4490 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4491 results.extend(
4492 input_api.RunTests(
4493 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174494
Bruce Dawsonc8054482022-03-28 15:33:374495 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504496 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374497 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504498 results.extend(
4499 input_api.RunTests(
4500 input_api.canned_checks.CheckDirMetadataFormat(
4501 input_api, output_api, dirmd_bin)))
4502 results.extend(
4503 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4504 input_api, output_api))
4505 results.extend(
4506 input_api.canned_checks.CheckNoNewMetadataInOwners(
4507 input_api, output_api))
4508 results.extend(
4509 input_api.canned_checks.CheckInclusiveLanguage(
4510 input_api,
4511 output_api,
4512 excluded_directories_relative_path=[
4513 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4514 ],
4515 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594516
Sam Maiera6e76d72022-02-11 21:43:504517 for f in input_api.AffectedFiles():
4518 path, name = input_api.os_path.split(f.LocalPath())
4519 if name == 'PRESUBMIT.py':
4520 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4521 path)
4522 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4523 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4524 # The PRESUBMIT.py file (and the directory containing it) might
4525 # have been affected by being moved or removed, so only try to
4526 # run the tests if they still exist.
4527 use_python3 = False
4528 with open(f.LocalPath()) as fp:
4529 use_python3 = any(
4530 line.startswith('USE_PYTHON3 = True')
4531 for line in fp.readlines())
4532
4533 results.extend(
4534 input_api.canned_checks.RunUnitTestsInDirectory(
4535 input_api,
4536 output_api,
4537 full_path,
4538 files_to_check=[r'^PRESUBMIT_test\.py$'],
4539 run_on_python2=not use_python3,
4540 run_on_python3=use_python3,
4541 skip_shebang_check=True))
4542 return results
[email protected]1f7b4172010-01-28 01:17:344543
[email protected]b337cb5b2011-01-23 21:24:054544
Saagar Sanghavifceeaae2020-08-12 16:40:364545def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504546 problems = [
4547 f.LocalPath() for f in input_api.AffectedFiles()
4548 if f.LocalPath().endswith(('.orig', '.rej'))
4549 ]
4550 # Cargo.toml.orig files are part of third-party crates downloaded from
4551 # crates.io and should be included.
4552 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4553 if problems:
4554 return [
4555 output_api.PresubmitError("Don't commit .rej and .orig files.",
4556 problems)
4557 ]
4558 else:
4559 return []
[email protected]b8079ae4a2012-12-05 19:56:494560
4561
Saagar Sanghavifceeaae2020-08-12 16:40:364562def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504563 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4564 macro_re = input_api.re.compile(
4565 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4566 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4567 input_api.re.MULTILINE)
4568 extension_re = input_api.re.compile(r'\.[a-z]+$')
4569 errors = []
4570 for f in input_api.AffectedFiles(include_deletes=False):
4571 if not f.LocalPath().endswith(
4572 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4573 continue
4574 found_line_number = None
4575 found_macro = None
4576 all_lines = input_api.ReadFile(f, 'r').splitlines()
4577 for line_num, line in enumerate(all_lines):
4578 match = macro_re.search(line)
4579 if match:
4580 found_line_number = line_num
4581 found_macro = match.group(2)
4582 break
4583 if not found_line_number:
4584 continue
Kent Tamura5a8755d2017-06-29 23:37:074585
Sam Maiera6e76d72022-02-11 21:43:504586 found_include_line = -1
4587 for line_num, line in enumerate(all_lines):
4588 if include_re.search(line):
4589 found_include_line = line_num
4590 break
4591 if found_include_line >= 0 and found_include_line < found_line_number:
4592 continue
Kent Tamura5a8755d2017-06-29 23:37:074593
Sam Maiera6e76d72022-02-11 21:43:504594 if not f.LocalPath().endswith('.h'):
4595 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4596 try:
4597 content = input_api.ReadFile(primary_header_path, 'r')
4598 if include_re.search(content):
4599 continue
4600 except IOError:
4601 pass
4602 errors.append('%s:%d %s macro is used without first including build/'
4603 'build_config.h.' %
4604 (f.LocalPath(), found_line_number, found_macro))
4605 if errors:
4606 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4607 return []
Kent Tamura5a8755d2017-06-29 23:37:074608
4609
Lei Zhang1c12a22f2021-05-12 11:28:454610def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504611 stl_include_re = input_api.re.compile(r'^#include\s+<('
4612 r'algorithm|'
4613 r'array|'
4614 r'limits|'
4615 r'list|'
4616 r'map|'
4617 r'memory|'
4618 r'queue|'
4619 r'set|'
4620 r'string|'
4621 r'unordered_map|'
4622 r'unordered_set|'
4623 r'utility|'
4624 r'vector)>')
4625 std_namespace_re = input_api.re.compile(r'std::')
4626 errors = []
4627 for f in input_api.AffectedFiles():
4628 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4629 continue
Lei Zhang1c12a22f2021-05-12 11:28:454630
Sam Maiera6e76d72022-02-11 21:43:504631 uses_std_namespace = False
4632 has_stl_include = False
4633 for line in f.NewContents():
4634 if has_stl_include and uses_std_namespace:
4635 break
Lei Zhang1c12a22f2021-05-12 11:28:454636
Sam Maiera6e76d72022-02-11 21:43:504637 if not has_stl_include and stl_include_re.search(line):
4638 has_stl_include = True
4639 continue
Lei Zhang1c12a22f2021-05-12 11:28:454640
Bruce Dawson4a5579a2022-04-08 17:11:364641 if not uses_std_namespace and (std_namespace_re.search(line)
4642 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504643 uses_std_namespace = True
4644 continue
Lei Zhang1c12a22f2021-05-12 11:28:454645
Sam Maiera6e76d72022-02-11 21:43:504646 if has_stl_include and not uses_std_namespace:
4647 errors.append(
4648 '%s: Includes STL header(s) but does not reference std::' %
4649 f.LocalPath())
4650 if errors:
4651 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4652 return []
Lei Zhang1c12a22f2021-05-12 11:28:454653
4654
Xiaohan Wang42d96c22022-01-20 17:23:114655def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504656 """Check for sensible looking, totally invalid OS macros."""
4657 preprocessor_statement = input_api.re.compile(r'^\s*#')
4658 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4659 results = []
4660 for lnum, line in f.ChangedContents():
4661 if preprocessor_statement.search(line):
4662 for match in os_macro.finditer(line):
4663 results.append(
4664 ' %s:%d: %s' %
4665 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4666 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4667 return results
[email protected]b00342e7f2013-03-26 16:21:544668
4669
Xiaohan Wang42d96c22022-01-20 17:23:114670def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504671 """Check all affected files for invalid OS macros."""
4672 bad_macros = []
4673 for f in input_api.AffectedSourceFiles(None):
4674 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4675 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544676
Sam Maiera6e76d72022-02-11 21:43:504677 if not bad_macros:
4678 return []
[email protected]b00342e7f2013-03-26 16:21:544679
Sam Maiera6e76d72022-02-11 21:43:504680 return [
4681 output_api.PresubmitError(
4682 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4683 'defined in build_config.h):', bad_macros)
4684 ]
[email protected]b00342e7f2013-03-26 16:21:544685
lliabraa35bab3932014-10-01 12:16:444686
4687def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504688 """Check all affected files for invalid "if defined" macros."""
4689 ALWAYS_DEFINED_MACROS = (
4690 "TARGET_CPU_PPC",
4691 "TARGET_CPU_PPC64",
4692 "TARGET_CPU_68K",
4693 "TARGET_CPU_X86",
4694 "TARGET_CPU_ARM",
4695 "TARGET_CPU_MIPS",
4696 "TARGET_CPU_SPARC",
4697 "TARGET_CPU_ALPHA",
4698 "TARGET_IPHONE_SIMULATOR",
4699 "TARGET_OS_EMBEDDED",
4700 "TARGET_OS_IPHONE",
4701 "TARGET_OS_MAC",
4702 "TARGET_OS_UNIX",
4703 "TARGET_OS_WIN32",
4704 )
4705 ifdef_macro = input_api.re.compile(
4706 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4707 results = []
4708 for lnum, line in f.ChangedContents():
4709 for match in ifdef_macro.finditer(line):
4710 if match.group(1) in ALWAYS_DEFINED_MACROS:
4711 always_defined = ' %s is always defined. ' % match.group(1)
4712 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4713 results.append(
4714 ' %s:%d %s\n\t%s' %
4715 (f.LocalPath(), lnum, always_defined, did_you_mean))
4716 return results
lliabraa35bab3932014-10-01 12:16:444717
4718
Saagar Sanghavifceeaae2020-08-12 16:40:364719def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504720 """Check all affected files for invalid "if defined" macros."""
4721 bad_macros = []
4722 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4723 for f in input_api.AffectedFiles():
4724 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4725 continue
4726 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4727 bad_macros.extend(
4728 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444729
Sam Maiera6e76d72022-02-11 21:43:504730 if not bad_macros:
4731 return []
lliabraa35bab3932014-10-01 12:16:444732
Sam Maiera6e76d72022-02-11 21:43:504733 return [
4734 output_api.PresubmitError(
4735 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4736 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4737 bad_macros)
4738 ]
lliabraa35bab3932014-10-01 12:16:444739
4740
Saagar Sanghavifceeaae2020-08-12 16:40:364741def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504742 """Check for same IPC rules described in
4743 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4744 """
4745 base_pattern = r'IPC_ENUM_TRAITS\('
4746 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4747 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044748
Sam Maiera6e76d72022-02-11 21:43:504749 problems = []
4750 for f in input_api.AffectedSourceFiles(None):
4751 local_path = f.LocalPath()
4752 if not local_path.endswith('.h'):
4753 continue
4754 for line_number, line in f.ChangedContents():
4755 if inclusion_pattern.search(
4756 line) and not comment_pattern.search(line):
4757 problems.append('%s:%d\n %s' %
4758 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044759
Sam Maiera6e76d72022-02-11 21:43:504760 if problems:
4761 return [
4762 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4763 problems)
4764 ]
4765 else:
4766 return []
mlamouria82272622014-09-16 18:45:044767
[email protected]b00342e7f2013-03-26 16:21:544768
Saagar Sanghavifceeaae2020-08-12 16:40:364769def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504770 """Check to make sure no files being submitted have long paths.
4771 This causes issues on Windows.
4772 """
4773 problems = []
4774 for f in input_api.AffectedTestableFiles():
4775 local_path = f.LocalPath()
4776 # Windows has a path limit of 260 characters. Limit path length to 200 so
4777 # that we have some extra for the prefix on dev machines and the bots.
4778 if len(local_path) > 200:
4779 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054780
Sam Maiera6e76d72022-02-11 21:43:504781 if problems:
4782 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4783 else:
4784 return []
Stephen Martinis97a394142018-06-07 23:06:054785
4786
Saagar Sanghavifceeaae2020-08-12 16:40:364787def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504788 """Check that header files have proper guards against multiple inclusion.
4789 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364790 should include the string "no-include-guard-because-multiply-included" or
4791 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504792 """
Daniel Bratell8ba52722018-03-02 16:06:144793
Sam Maiera6e76d72022-02-11 21:43:504794 def is_chromium_header_file(f):
4795 # We only check header files under the control of the Chromium
4796 # project. That is, those outside third_party apart from
4797 # third_party/blink.
4798 # We also exclude *_message_generator.h headers as they use
4799 # include guards in a special, non-typical way.
4800 file_with_path = input_api.os_path.normpath(f.LocalPath())
4801 return (file_with_path.endswith('.h')
4802 and not file_with_path.endswith('_message_generator.h')
4803 and (not file_with_path.startswith('third_party')
4804 or file_with_path.startswith(
4805 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144806
Sam Maiera6e76d72022-02-11 21:43:504807 def replace_special_with_underscore(string):
4808 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144809
Sam Maiera6e76d72022-02-11 21:43:504810 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144811
Sam Maiera6e76d72022-02-11 21:43:504812 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4813 guard_name = None
4814 guard_line_number = None
4815 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144816
Sam Maiera6e76d72022-02-11 21:43:504817 file_with_path = input_api.os_path.normpath(f.LocalPath())
4818 base_file_name = input_api.os_path.splitext(
4819 input_api.os_path.basename(file_with_path))[0]
4820 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144821
Sam Maiera6e76d72022-02-11 21:43:504822 expected_guard = replace_special_with_underscore(
4823 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144824
Sam Maiera6e76d72022-02-11 21:43:504825 # For "path/elem/file_name.h" we should really only accept
4826 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4827 # are too many (1000+) files with slight deviations from the
4828 # coding style. The most important part is that the include guard
4829 # is there, and that it's unique, not the name so this check is
4830 # forgiving for existing files.
4831 #
4832 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144833
Sam Maiera6e76d72022-02-11 21:43:504834 guard_name_pattern_list = [
4835 # Anything with the right suffix (maybe with an extra _).
4836 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144837
Sam Maiera6e76d72022-02-11 21:43:504838 # To cover include guards with old Blink style.
4839 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144840
Sam Maiera6e76d72022-02-11 21:43:504841 # Anything including the uppercase name of the file.
4842 r'\w*' + input_api.re.escape(
4843 replace_special_with_underscore(upper_base_file_name)) +
4844 r'\w*',
4845 ]
4846 guard_name_pattern = '|'.join(guard_name_pattern_list)
4847 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4848 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144849
Sam Maiera6e76d72022-02-11 21:43:504850 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364851 if ('no-include-guard-because-multiply-included' in line
4852 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504853 guard_name = 'DUMMY' # To not trigger check outside the loop.
4854 break
Daniel Bratell8ba52722018-03-02 16:06:144855
Sam Maiera6e76d72022-02-11 21:43:504856 if guard_name is None:
4857 match = guard_pattern.match(line)
4858 if match:
4859 guard_name = match.group(1)
4860 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144861
Sam Maiera6e76d72022-02-11 21:43:504862 # We allow existing files to use include guards whose names
4863 # don't match the chromium style guide, but new files should
4864 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494865 if guard_name != expected_guard:
4866 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504867 errors.append(
4868 output_api.PresubmitPromptWarning(
4869 'Header using the wrong include guard name %s'
4870 % guard_name, [
4871 '%s:%d' %
4872 (f.LocalPath(), line_number + 1)
4873 ], 'Expected: %r\nFound: %r' %
4874 (expected_guard, guard_name)))
4875 else:
4876 # The line after #ifndef should have a #define of the same name.
4877 if line_number == guard_line_number + 1:
4878 expected_line = '#define %s' % guard_name
4879 if line != expected_line:
4880 errors.append(
4881 output_api.PresubmitPromptWarning(
4882 'Missing "%s" for include guard' %
4883 expected_line,
4884 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4885 'Expected: %r\nGot: %r' %
4886 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144887
Sam Maiera6e76d72022-02-11 21:43:504888 if not seen_guard_end and line == '#endif // %s' % guard_name:
4889 seen_guard_end = True
4890 elif seen_guard_end:
4891 if line.strip() != '':
4892 errors.append(
4893 output_api.PresubmitPromptWarning(
4894 'Include guard %s not covering the whole file'
4895 % (guard_name), [f.LocalPath()]))
4896 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144897
Sam Maiera6e76d72022-02-11 21:43:504898 if guard_name is None:
4899 errors.append(
4900 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494901 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504902 'Recommended name: %s\n'
4903 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364904 '"no-include-guard-because-multiply-included" or\n'
4905 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504906 % (f.LocalPath(), expected_guard)))
4907
4908 return errors
Daniel Bratell8ba52722018-03-02 16:06:144909
4910
Saagar Sanghavifceeaae2020-08-12 16:40:364911def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504912 """Check source code and known ascii text files for Windows style line
4913 endings.
4914 """
Bruce Dawson5efbdc652022-04-11 19:29:514915 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234916
Sam Maiera6e76d72022-02-11 21:43:504917 file_inclusion_pattern = (known_text_files,
4918 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4919 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:234920
Sam Maiera6e76d72022-02-11 21:43:504921 problems = []
4922 source_file_filter = lambda f: input_api.FilterSourceFile(
4923 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
4924 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:514925 # Ignore test files that contain crlf intentionally.
4926 if f.LocalPath().endswith('crlf.txt'):
4927 continue
Sam Maiera6e76d72022-02-11 21:43:504928 include_file = False
4929 for line in input_api.ReadFile(f, 'r').splitlines(True):
4930 if line.endswith('\r\n'):
4931 include_file = True
4932 if include_file:
4933 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234934
Sam Maiera6e76d72022-02-11 21:43:504935 if problems:
4936 return [
4937 output_api.PresubmitPromptWarning(
4938 'Are you sure that you want '
4939 'these files to contain Windows style line endings?\n' +
4940 '\n'.join(problems))
4941 ]
mostynbb639aca52015-01-07 20:31:234942
Sam Maiera6e76d72022-02-11 21:43:504943 return []
4944
mostynbb639aca52015-01-07 20:31:234945
Evan Stade6cfc964c12021-05-18 20:21:164946def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504947 """Check that .icon files (which are fragments of C++) have license headers.
4948 """
Evan Stade6cfc964c12021-05-18 20:21:164949
Sam Maiera6e76d72022-02-11 21:43:504950 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:164951
Sam Maiera6e76d72022-02-11 21:43:504952 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4953 return input_api.canned_checks.CheckLicense(input_api,
4954 output_api,
4955 source_file_filter=icons)
4956
Evan Stade6cfc964c12021-05-18 20:21:164957
Jose Magana2b456f22021-03-09 23:26:404958def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504959 """Check source code for use of Chrome App technologies being
4960 deprecated.
4961 """
Jose Magana2b456f22021-03-09 23:26:404962
Sam Maiera6e76d72022-02-11 21:43:504963 def _CheckForDeprecatedTech(input_api,
4964 output_api,
4965 detection_list,
4966 files_to_check=None,
4967 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:404968
Sam Maiera6e76d72022-02-11 21:43:504969 if (files_to_check or files_to_skip):
4970 source_file_filter = lambda f: input_api.FilterSourceFile(
4971 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
4972 else:
4973 source_file_filter = None
4974
4975 problems = []
4976
4977 for f in input_api.AffectedSourceFiles(source_file_filter):
4978 if f.Action() == 'D':
4979 continue
4980 for _, line in f.ChangedContents():
4981 if any(detect in line for detect in detection_list):
4982 problems.append(f.LocalPath())
4983
4984 return problems
4985
4986 # to avoid this presubmit script triggering warnings
4987 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:404988
4989 problems = []
4990
Sam Maiera6e76d72022-02-11 21:43:504991 # NMF: any files with extensions .nmf or NMF
4992 _NMF_FILES = r'\.(nmf|NMF)$'
4993 problems += _CheckForDeprecatedTech(
4994 input_api,
4995 output_api,
4996 detection_list=[''], # any change to the file will trigger warning
4997 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:404998
Sam Maiera6e76d72022-02-11 21:43:504999 # MANIFEST: any manifest.json that in its diff includes "app":
5000 _MANIFEST_FILES = r'(manifest\.json)$'
5001 problems += _CheckForDeprecatedTech(
5002 input_api,
5003 output_api,
5004 detection_list=['"app":'],
5005 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405006
Sam Maiera6e76d72022-02-11 21:43:505007 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5008 problems += _CheckForDeprecatedTech(
5009 input_api,
5010 output_api,
5011 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5012 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405013
Sam Maiera6e76d72022-02-11 21:43:505014 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5015 problems += _CheckForDeprecatedTech(
5016 input_api,
5017 output_api,
5018 detection_list=['#include "ppapi', '#include <ppapi'],
5019 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5020 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5021 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405022
Sam Maiera6e76d72022-02-11 21:43:505023 if problems:
5024 return [
5025 output_api.PresubmitPromptWarning(
5026 'You are adding/modifying code'
5027 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5028 ' PNaCl, PPAPI). See this blog post for more details:\n'
5029 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5030 'and this documentation for options to replace these technologies:\n'
5031 'https://developer.chrome.com/docs/apps/migration/\n' +
5032 '\n'.join(problems))
5033 ]
Jose Magana2b456f22021-03-09 23:26:405034
Sam Maiera6e76d72022-02-11 21:43:505035 return []
Jose Magana2b456f22021-03-09 23:26:405036
mostynbb639aca52015-01-07 20:31:235037
Saagar Sanghavifceeaae2020-08-12 16:40:365038def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505039 """Checks that all source files use SYSLOG properly."""
5040 syslog_files = []
5041 for f in input_api.AffectedSourceFiles(src_file_filter):
5042 for line_number, line in f.ChangedContents():
5043 if 'SYSLOG' in line:
5044 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565045
Sam Maiera6e76d72022-02-11 21:43:505046 if syslog_files:
5047 return [
5048 output_api.PresubmitPromptWarning(
5049 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5050 ' calls.\nFiles to check:\n',
5051 items=syslog_files)
5052 ]
5053 return []
pastarmovj89f7ee12016-09-20 14:58:135054
5055
[email protected]1f7b4172010-01-28 01:17:345056def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505057 if input_api.version < [2, 0, 0]:
5058 return [
5059 output_api.PresubmitError(
5060 "Your depot_tools is out of date. "
5061 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5062 "but your version is %d.%d.%d" % tuple(input_api.version))
5063 ]
5064 results = []
5065 results.extend(
5066 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5067 return results
[email protected]ca8d1982009-02-19 16:33:125068
5069
5070def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505071 if input_api.version < [2, 0, 0]:
5072 return [
5073 output_api.PresubmitError(
5074 "Your depot_tools is out of date. "
5075 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5076 "but your version is %d.%d.%d" % tuple(input_api.version))
5077 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365078
Sam Maiera6e76d72022-02-11 21:43:505079 results = []
5080 # Make sure the tree is 'open'.
5081 results.extend(
5082 input_api.canned_checks.CheckTreeIsOpen(
5083 input_api,
5084 output_api,
5085 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275086
Sam Maiera6e76d72022-02-11 21:43:505087 results.extend(
5088 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5089 results.extend(
5090 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5091 results.extend(
5092 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5093 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505094 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145095
5096
Saagar Sanghavifceeaae2020-08-12 16:40:365097def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505098 """Check string ICU syntax validity and if translation screenshots exist."""
5099 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5100 # footer is set to true.
5101 git_footers = input_api.change.GitFootersFromDescription()
5102 skip_screenshot_check_footer = [
5103 footer.lower() for footer in git_footers.get(
5104 u'Skip-Translation-Screenshots-Check', [])
5105 ]
5106 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025107
Sam Maiera6e76d72022-02-11 21:43:505108 import os
5109 import re
5110 import sys
5111 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145112
Sam Maiera6e76d72022-02-11 21:43:505113 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5114 if (f.Action() == 'A' or f.Action() == 'M'))
5115 removed_paths = set(f.LocalPath()
5116 for f in input_api.AffectedFiles(include_deletes=True)
5117 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145118
Sam Maiera6e76d72022-02-11 21:43:505119 affected_grds = [
5120 f for f in input_api.AffectedFiles()
5121 if f.LocalPath().endswith(('.grd', '.grdp'))
5122 ]
5123 affected_grds = [
5124 f for f in affected_grds if not 'testdata' in f.LocalPath()
5125 ]
5126 if not affected_grds:
5127 return []
meacer8c0d3832019-12-26 21:46:165128
Sam Maiera6e76d72022-02-11 21:43:505129 affected_png_paths = [
5130 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5131 if (f.LocalPath().endswith('.png'))
5132 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145133
Sam Maiera6e76d72022-02-11 21:43:505134 # Check for screenshots. Developers can upload screenshots using
5135 # tools/translation/upload_screenshots.py which finds and uploads
5136 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5137 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5138 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5139 #
5140 # The logic here is as follows:
5141 #
5142 # - If the CL has a .png file under the screenshots directory for a grd
5143 # file, warn the developer. Actual images should never be checked into the
5144 # Chrome repo.
5145 #
5146 # - If the CL contains modified or new messages in grd files and doesn't
5147 # contain the corresponding .sha1 files, warn the developer to add images
5148 # and upload them via tools/translation/upload_screenshots.py.
5149 #
5150 # - If the CL contains modified or new messages in grd files and the
5151 # corresponding .sha1 files, everything looks good.
5152 #
5153 # - If the CL contains removed messages in grd files but the corresponding
5154 # .sha1 files aren't removed, warn the developer to remove them.
5155 unnecessary_screenshots = []
5156 missing_sha1 = []
5157 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145158
Sam Maiera6e76d72022-02-11 21:43:505159 # This checks verifies that the ICU syntax of messages this CL touched is
5160 # valid, and reports any found syntax errors.
5161 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5162 # without developers being aware of them. Later on, such ICU syntax errors
5163 # break message extraction for translation, hence would block Chromium
5164 # translations until they are fixed.
5165 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145166
Sam Maiera6e76d72022-02-11 21:43:505167 def _CheckScreenshotAdded(screenshots_dir, message_id):
5168 sha1_path = input_api.os_path.join(screenshots_dir,
5169 message_id + '.png.sha1')
5170 if sha1_path not in new_or_added_paths:
5171 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145172
Sam Maiera6e76d72022-02-11 21:43:505173 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5174 sha1_path = input_api.os_path.join(screenshots_dir,
5175 message_id + '.png.sha1')
5176 if input_api.os_path.exists(
5177 sha1_path) and sha1_path not in removed_paths:
5178 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145179
Sam Maiera6e76d72022-02-11 21:43:505180 def _ValidateIcuSyntax(text, level, signatures):
5181 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145182
Sam Maiera6e76d72022-02-11 21:43:505183 Check if text looks similar to ICU and checks for ICU syntax correctness
5184 in this case. Reports various issues with ICU syntax and values of
5185 variants. Supports checking of nested messages. Accumulate information of
5186 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265187
Sam Maiera6e76d72022-02-11 21:43:505188 Args:
5189 text: a string to check.
5190 level: a number of current nesting level.
5191 signatures: an accumulator, a list of tuple of (level, variable,
5192 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265193
Sam Maiera6e76d72022-02-11 21:43:505194 Returns:
5195 None if a string is not ICU or no issue detected.
5196 A tuple of (message, start index, end index) if an issue detected.
5197 """
5198 valid_types = {
5199 'plural': (frozenset(
5200 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5201 'other']), frozenset(['=1', 'other'])),
5202 'selectordinal': (frozenset(
5203 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5204 'other']), frozenset(['one', 'other'])),
5205 'select': (frozenset(), frozenset(['other'])),
5206 }
Rainhard Findlingfc31844c52020-05-15 09:58:265207
Sam Maiera6e76d72022-02-11 21:43:505208 # Check if the message looks like an attempt to use ICU
5209 # plural. If yes - check if its syntax strictly matches ICU format.
5210 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5211 text)
5212 if not like:
5213 signatures.append((level, None, None, None))
5214 return
Rainhard Findlingfc31844c52020-05-15 09:58:265215
Sam Maiera6e76d72022-02-11 21:43:505216 # Check for valid prefix and suffix
5217 m = re.match(
5218 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5219 r'(plural|selectordinal|select),\s*'
5220 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5221 if not m:
5222 return (('This message looks like an ICU plural, '
5223 'but does not follow ICU syntax.'), like.start(),
5224 like.end())
5225 starting, variable, kind, variant_pairs = m.groups()
5226 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5227 m.start(4))
5228 if depth:
5229 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5230 len(text))
5231 first = text[0]
5232 ending = text[last_pos:]
5233 if not starting:
5234 return ('Invalid ICU format. No initial opening bracket',
5235 last_pos - 1, last_pos)
5236 if not ending or '}' not in ending:
5237 return ('Invalid ICU format. No final closing bracket',
5238 last_pos - 1, last_pos)
5239 elif first != '{':
5240 return ((
5241 'Invalid ICU format. Extra characters at the start of a complex '
5242 'message (go/icu-message-migration): "%s"') % starting, 0,
5243 len(starting))
5244 elif ending != '}':
5245 return ((
5246 'Invalid ICU format. Extra characters at the end of a complex '
5247 'message (go/icu-message-migration): "%s"') % ending,
5248 last_pos - 1, len(text) - 1)
5249 if kind not in valid_types:
5250 return (('Unknown ICU message type %s. '
5251 'Valid types are: plural, select, selectordinal') % kind,
5252 0, 0)
5253 known, required = valid_types[kind]
5254 defined_variants = set()
5255 for variant, variant_range, value, value_range in variants:
5256 start, end = variant_range
5257 if variant in defined_variants:
5258 return ('Variant "%s" is defined more than once' % variant,
5259 start, end)
5260 elif known and variant not in known:
5261 return ('Variant "%s" is not valid for %s message' %
5262 (variant, kind), start, end)
5263 defined_variants.add(variant)
5264 # Check for nested structure
5265 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5266 if res:
5267 return (res[0], res[1] + value_range[0] + 1,
5268 res[2] + value_range[0] + 1)
5269 missing = required - defined_variants
5270 if missing:
5271 return ('Required variants missing: %s' % ', '.join(missing), 0,
5272 len(text))
5273 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265274
Sam Maiera6e76d72022-02-11 21:43:505275 def _ParseIcuVariants(text, offset=0):
5276 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265277
Sam Maiera6e76d72022-02-11 21:43:505278 Builds a tuple of variant names and values, as well as
5279 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265280
Sam Maiera6e76d72022-02-11 21:43:505281 Args:
5282 text: a string to parse
5283 offset: additional offset to add to positions in the text to get correct
5284 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265285
Sam Maiera6e76d72022-02-11 21:43:505286 Returns:
5287 List of tuples, each tuple consist of four fields: variant name,
5288 variant name span (tuple of two integers), variant value, value
5289 span (tuple of two integers).
5290 """
5291 depth, start, end = 0, -1, -1
5292 variants = []
5293 key = None
5294 for idx, char in enumerate(text):
5295 if char == '{':
5296 if not depth:
5297 start = idx
5298 chunk = text[end + 1:start]
5299 key = chunk.strip()
5300 pos = offset + end + 1 + chunk.find(key)
5301 span = (pos, pos + len(key))
5302 depth += 1
5303 elif char == '}':
5304 if not depth:
5305 return variants, depth, offset + idx
5306 depth -= 1
5307 if not depth:
5308 end = idx
5309 variants.append((key, span, text[start:end + 1],
5310 (offset + start, offset + end + 1)))
5311 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265312
Sam Maiera6e76d72022-02-11 21:43:505313 try:
5314 old_sys_path = sys.path
5315 sys.path = sys.path + [
5316 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5317 'translation')
5318 ]
5319 from helper import grd_helper
5320 finally:
5321 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265322
Sam Maiera6e76d72022-02-11 21:43:505323 for f in affected_grds:
5324 file_path = f.LocalPath()
5325 old_id_to_msg_map = {}
5326 new_id_to_msg_map = {}
5327 # Note that this code doesn't check if the file has been deleted. This is
5328 # OK because it only uses the old and new file contents and doesn't load
5329 # the file via its path.
5330 # It's also possible that a file's content refers to a renamed or deleted
5331 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5332 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5333 # .grdp files.
5334 if file_path.endswith('.grdp'):
5335 if f.OldContents():
5336 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5337 '\n'.join(f.OldContents()))
5338 if f.NewContents():
5339 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5340 '\n'.join(f.NewContents()))
5341 else:
5342 file_dir = input_api.os_path.dirname(file_path) or '.'
5343 if f.OldContents():
5344 old_id_to_msg_map = grd_helper.GetGrdMessages(
5345 StringIO('\n'.join(f.OldContents())), file_dir)
5346 if f.NewContents():
5347 new_id_to_msg_map = grd_helper.GetGrdMessages(
5348 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265349
Sam Maiera6e76d72022-02-11 21:43:505350 grd_name, ext = input_api.os_path.splitext(
5351 input_api.os_path.basename(file_path))
5352 screenshots_dir = input_api.os_path.join(
5353 input_api.os_path.dirname(file_path),
5354 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265355
Sam Maiera6e76d72022-02-11 21:43:505356 # Compute added, removed and modified message IDs.
5357 old_ids = set(old_id_to_msg_map)
5358 new_ids = set(new_id_to_msg_map)
5359 added_ids = new_ids - old_ids
5360 removed_ids = old_ids - new_ids
5361 modified_ids = set([])
5362 for key in old_ids.intersection(new_ids):
5363 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5364 new_id_to_msg_map[key].ContentsAsXml('', True)):
5365 # The message content itself changed. Require an updated screenshot.
5366 modified_ids.add(key)
5367 elif old_id_to_msg_map[key].attrs['meaning'] != \
5368 new_id_to_msg_map[key].attrs['meaning']:
5369 # The message meaning changed. Ensure there is a screenshot for it.
5370 sha1_path = input_api.os_path.join(screenshots_dir,
5371 key + '.png.sha1')
5372 if sha1_path not in new_or_added_paths and not \
5373 input_api.os_path.exists(sha1_path):
5374 # There is neither a previous screenshot nor is a new one added now.
5375 # Require a screenshot.
5376 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145377
Sam Maiera6e76d72022-02-11 21:43:505378 if run_screenshot_check:
5379 # Check the screenshot directory for .png files. Warn if there is any.
5380 for png_path in affected_png_paths:
5381 if png_path.startswith(screenshots_dir):
5382 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145383
Sam Maiera6e76d72022-02-11 21:43:505384 for added_id in added_ids:
5385 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095386
Sam Maiera6e76d72022-02-11 21:43:505387 for modified_id in modified_ids:
5388 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145389
Sam Maiera6e76d72022-02-11 21:43:505390 for removed_id in removed_ids:
5391 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5392
5393 # Check new and changed strings for ICU syntax errors.
5394 for key in added_ids.union(modified_ids):
5395 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5396 err = _ValidateIcuSyntax(msg, 0, [])
5397 if err is not None:
5398 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5399
5400 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265401 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505402 if unnecessary_screenshots:
5403 results.append(
5404 output_api.PresubmitError(
5405 'Do not include actual screenshots in the changelist. Run '
5406 'tools/translate/upload_screenshots.py to upload them instead:',
5407 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145408
Sam Maiera6e76d72022-02-11 21:43:505409 if missing_sha1:
5410 results.append(
5411 output_api.PresubmitError(
5412 'You are adding or modifying UI strings.\n'
5413 'To ensure the best translations, take screenshots of the relevant UI '
5414 '(https://g.co/chrome/translation) and add these files to your '
5415 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145416
Sam Maiera6e76d72022-02-11 21:43:505417 if unnecessary_sha1_files:
5418 results.append(
5419 output_api.PresubmitError(
5420 'You removed strings associated with these files. Remove:',
5421 sorted(unnecessary_sha1_files)))
5422 else:
5423 results.append(
5424 output_api.PresubmitPromptOrNotify('Skipping translation '
5425 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145426
Sam Maiera6e76d72022-02-11 21:43:505427 if icu_syntax_errors:
5428 results.append(
5429 output_api.PresubmitPromptWarning(
5430 'ICU syntax errors were found in the following strings (problems or '
5431 'feedback? Contact [email protected]):',
5432 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265433
Sam Maiera6e76d72022-02-11 21:43:505434 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125435
5436
Saagar Sanghavifceeaae2020-08-12 16:40:365437def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125438 repo_root=None,
5439 translation_expectations_path=None,
5440 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505441 import sys
5442 affected_grds = [
5443 f for f in input_api.AffectedFiles()
5444 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5445 ]
5446 if not affected_grds:
5447 return []
5448
5449 try:
5450 old_sys_path = sys.path
5451 sys.path = sys.path + [
5452 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5453 'translation')
5454 ]
5455 from helper import git_helper
5456 from helper import translation_helper
5457 finally:
5458 sys.path = old_sys_path
5459
5460 # Check that translation expectations can be parsed and we can get a list of
5461 # translatable grd files. |repo_root| and |translation_expectations_path| are
5462 # only passed by tests.
5463 if not repo_root:
5464 repo_root = input_api.PresubmitLocalPath()
5465 if not translation_expectations_path:
5466 translation_expectations_path = input_api.os_path.join(
5467 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5468 if not grd_files:
5469 grd_files = git_helper.list_grds_in_repository(repo_root)
5470
5471 # Ignore bogus grd files used only for testing
5472 # ui/webui/resoucres/tools/generate_grd.py.
5473 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5474 'tests')
5475 grd_files = [p for p in grd_files if ignore_path not in p]
5476
5477 try:
5478 translation_helper.get_translatable_grds(
5479 repo_root, grd_files, translation_expectations_path)
5480 except Exception as e:
5481 return [
5482 output_api.PresubmitNotifyResult(
5483 'Failed to get a list of translatable grd files. This happens when:\n'
5484 ' - One of the modified grd or grdp files cannot be parsed or\n'
5485 ' - %s is not updated.\n'
5486 'Stack:\n%s' % (translation_expectations_path, str(e)))
5487 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125488 return []
5489
Ken Rockotc31f4832020-05-29 18:58:515490
Saagar Sanghavifceeaae2020-08-12 16:40:365491def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505492 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5493 changed_mojoms = input_api.AffectedFiles(
5494 include_deletes=True,
5495 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525496
Sam Maiera6e76d72022-02-11 21:43:505497 if not changed_mojoms:
5498 return []
5499
5500 delta = []
5501 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505502 delta.append({
5503 'filename': mojom.LocalPath(),
5504 'old': '\n'.join(mojom.OldContents()) or None,
5505 'new': '\n'.join(mojom.NewContents()) or None,
5506 })
5507
5508 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215509 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505510 input_api.os_path.join(
5511 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5512 'check_stable_mojom_compatibility.py'), '--src-root',
5513 input_api.PresubmitLocalPath()
5514 ],
5515 stdin=input_api.subprocess.PIPE,
5516 stdout=input_api.subprocess.PIPE,
5517 stderr=input_api.subprocess.PIPE,
5518 universal_newlines=True)
5519 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5520 if process.returncode:
5521 return [
5522 output_api.PresubmitError(
5523 'One or more [Stable] mojom definitions appears to have been changed '
5524 'in a way that is not backward-compatible.',
5525 long_text=error)
5526 ]
Erik Staabc734cd7a2021-11-23 03:11:525527 return []
5528
Dominic Battre645d42342020-12-04 16:14:105529def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505530 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105531
Sam Maiera6e76d72022-02-11 21:43:505532 def FilterFile(affected_file):
5533 """Accept only .cc files and the like."""
5534 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5535 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5536 input_api.DEFAULT_FILES_TO_SKIP)
5537 return input_api.FilterSourceFile(
5538 affected_file,
5539 files_to_check=file_inclusion_pattern,
5540 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105541
Sam Maiera6e76d72022-02-11 21:43:505542 def ModifiedLines(affected_file):
5543 """Returns a list of tuples (line number, line text) of added and removed
5544 lines.
Dominic Battre645d42342020-12-04 16:14:105545
Sam Maiera6e76d72022-02-11 21:43:505546 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105547
Sam Maiera6e76d72022-02-11 21:43:505548 This relies on the scm diff output describing each changed code section
5549 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105550
Sam Maiera6e76d72022-02-11 21:43:505551 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5552 """
5553 line_num = 0
5554 modified_lines = []
5555 for line in affected_file.GenerateScmDiff().splitlines():
5556 # Extract <new line num> of the patch fragment (see format above).
5557 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5558 line)
5559 if m:
5560 line_num = int(m.groups(1)[0])
5561 continue
5562 if ((line.startswith('+') and not line.startswith('++'))
5563 or (line.startswith('-') and not line.startswith('--'))):
5564 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105565
Sam Maiera6e76d72022-02-11 21:43:505566 if not line.startswith('-'):
5567 line_num += 1
5568 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105569
Sam Maiera6e76d72022-02-11 21:43:505570 def FindLineWith(lines, needle):
5571 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105572
Sam Maiera6e76d72022-02-11 21:43:505573 If 0 or >1 lines contain `needle`, -1 is returned.
5574 """
5575 matching_line_numbers = [
5576 # + 1 for 1-based counting of line numbers.
5577 i + 1 for i, line in enumerate(lines) if needle in line
5578 ]
5579 return matching_line_numbers[0] if len(
5580 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105581
Sam Maiera6e76d72022-02-11 21:43:505582 def ModifiedPrefMigration(affected_file):
5583 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5584 # Determine first and last lines of MigrateObsolete.*Pref functions.
5585 new_contents = affected_file.NewContents()
5586 range_1 = (FindLineWith(new_contents,
5587 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5588 FindLineWith(new_contents,
5589 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5590 range_2 = (FindLineWith(new_contents,
5591 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5592 FindLineWith(new_contents,
5593 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5594 if (-1 in range_1 + range_2):
5595 raise Exception(
5596 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5597 )
Dominic Battre645d42342020-12-04 16:14:105598
Sam Maiera6e76d72022-02-11 21:43:505599 # Check whether any of the modified lines are part of the
5600 # MigrateObsolete.*Pref functions.
5601 for line_nr, line in ModifiedLines(affected_file):
5602 if (range_1[0] <= line_nr <= range_1[1]
5603 or range_2[0] <= line_nr <= range_2[1]):
5604 return True
5605 return False
Dominic Battre645d42342020-12-04 16:14:105606
Sam Maiera6e76d72022-02-11 21:43:505607 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5608 browser_prefs_file_pattern = input_api.re.compile(
5609 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105610
Sam Maiera6e76d72022-02-11 21:43:505611 changes = input_api.AffectedFiles(include_deletes=True,
5612 file_filter=FilterFile)
5613 potential_problems = []
5614 for f in changes:
5615 for line in f.GenerateScmDiff().splitlines():
5616 # Check deleted lines for pref registrations.
5617 if (line.startswith('-') and not line.startswith('--')
5618 and register_pref_pattern.search(line)):
5619 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105620
Sam Maiera6e76d72022-02-11 21:43:505621 if browser_prefs_file_pattern.search(f.LocalPath()):
5622 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5623 # assume that they knew that they have to deprecate preferences and don't
5624 # warn.
5625 try:
5626 if ModifiedPrefMigration(f):
5627 return []
5628 except Exception as e:
5629 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105630
Sam Maiera6e76d72022-02-11 21:43:505631 if potential_problems:
5632 return [
5633 output_api.PresubmitPromptWarning(
5634 'Discovered possible removal of preference registrations.\n\n'
5635 'Please make sure to properly deprecate preferences by clearing their\n'
5636 'value for a couple of milestones before finally removing the code.\n'
5637 'Otherwise data may stay in the preferences files forever. See\n'
5638 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5639 'chrome/browser/prefs/README.md for examples.\n'
5640 'This may be a false positive warning (e.g. if you move preference\n'
5641 'registrations to a different place).\n', potential_problems)
5642 ]
5643 return []
5644
Matt Stark6ef08872021-07-29 01:21:465645
5646def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505647 """Changes to GRD files must be consistent for tools to read them."""
5648 changed_grds = input_api.AffectedFiles(
5649 include_deletes=False,
5650 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5651 errors = []
5652 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5653 for matcher, msg in _INVALID_GRD_FILE_LINE]
5654 for grd in changed_grds:
5655 for i, line in enumerate(grd.NewContents()):
5656 for matcher, msg in invalid_file_regexes:
5657 if matcher.search(line):
5658 errors.append(
5659 output_api.PresubmitError(
5660 'Problem on {grd}:{i} - {msg}'.format(
5661 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5662 return errors
5663
Kevin McNee967dd2d22021-11-15 16:09:295664
5665def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505666 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5667 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5668 """
Kevin McNee967dd2d22021-11-15 16:09:295669
Ian Vollickdba956c2022-04-20 23:53:455670 # Only consider top-level directories that (1) can use content APIs or
5671 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5672 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505673 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455674 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295675 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455676 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505677 _HEADER_EXTENSIONS,
5678 )
5679 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5680 input_api.DEFAULT_FILES_TO_SKIP)
5681 source_file_filter = lambda f: input_api.FilterSourceFile(
5682 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295683
Sam Maiera6e76d72022-02-11 21:43:505684 # Note that since these are are just regular expressions and we don't have
5685 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5686 # could have a method named IsInMainFrame).
5687 concerning_class_pattern = input_api.re.compile(
5688 r'WebContentsObserver|WebContentsUserData')
5689 # A subset of WebContentsObserver overrides where there's particular risk for
5690 # confusing tab and page level operations and data (e.g. incorrectly
5691 # resetting page state in DidFinishNavigation).
5692 concerning_wco_methods = [
5693 'DidStartNavigation',
5694 'ReadyToCommitNavigation',
5695 'DidFinishNavigation',
5696 'RenderViewReady',
5697 'RenderViewDeleted',
5698 'RenderViewHostChanged',
5699 'PrimaryMainDocumentElementAvailable',
5700 'DocumentOnLoadCompletedInPrimaryMainFrame',
5701 'DOMContentLoaded',
5702 'DidFinishLoad',
5703 ]
5704 concerning_nav_handle_methods = [
5705 'IsInMainFrame',
5706 ]
5707 concerning_web_contents_methods = [
5708 'ForEachFrame',
5709 'GetAllFrames',
5710 'FromRenderFrameHost',
5711 'FromRenderViewHost',
5712 'GetMainFrame',
5713 'GetRenderViewHost',
5714 ]
5715 concerning_rfh_methods = [
5716 'GetParent',
5717 'GetMainFrame',
5718 'GetFrameTreeNodeId',
5719 ]
Ian Vollickc825b1f2022-04-19 14:30:155720 concerning_rfhi_methods = [
5721 'is_main_frame',
5722 ]
Ian Vollicka77a73ea2022-04-06 18:08:015723 concerning_ftn_methods = [
5724 'IsMainFrame',
5725 ]
Ian Vollickdba956c2022-04-20 23:53:455726 concerning_blink_frame_methods = [
5727 'IsCrossOriginToMainFrame',
5728 ]
Sam Maiera6e76d72022-02-11 21:43:505729 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5730 item for sublist in [
5731 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015732 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155733 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455734 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505735 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295736
Kevin McNee4eeec792022-02-14 20:02:045737 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505738 for f in input_api.AffectedFiles(include_deletes=False,
5739 file_filter=source_file_filter):
5740 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045741 class_match = concerning_class_pattern.search(line)
5742 if class_match:
5743 used_apis.add(class_match[0])
5744 method_match = concerning_method_pattern.search(line)
5745 if method_match:
5746 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505747
Kevin McNee4eeec792022-02-14 20:02:045748 if not used_apis:
5749 return []
Kevin McNee967dd2d22021-11-15 16:09:295750
Kevin McNee4eeec792022-02-14 20:02:045751 output_api.AppendCC('[email protected]')
5752 message = ('This change uses API(s) that are ambiguous in the presence of '
5753 'MPArch features such as bfcache, prerendering, and fenced '
5754 'frames.')
5755 explaination = (
5756 'Please double check whether new code assumes that a WebContents only '
5757 'contains a single page at a time. For example, it is discouraged to '
5758 'reset per-document state in response to the observation of a '
5759 'navigation. See this doc [1] and the comments on the individual APIs '
5760 'for guidance and this doc [2] for context. The MPArch review '
5761 'watchlist has been CC\'d on this change to help identify any issues.\n'
5762 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5763 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5764 )
5765 return [
5766 output_api.PresubmitNotifyResult(message,
5767 items=list(used_apis),
5768 long_text=explaination)
5769 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365770
5771
5772def CheckAssertAshOnlyCode(input_api, output_api):
5773 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5774 assert(is_chromeos_ash).
5775 """
5776
5777 def FileFilter(affected_file):
5778 """Includes directories known to be Ash only."""
5779 return input_api.FilterSourceFile(
5780 affected_file,
5781 files_to_check=(
5782 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5783 r'.*/ash/.*BUILD\.gn'), # Any path component.
5784 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5785
5786 errors = []
5787 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565788 for f in input_api.AffectedFiles(include_deletes=False,
5789 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365790 if (not pattern.search(input_api.ReadFile(f))):
5791 errors.append(
5792 output_api.PresubmitError(
5793 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5794 'possible, please create and issue and add a comment such '
5795 'as:\n # TODO(https://crbug.com/XXX): add '
5796 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5797 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275798
5799
5800def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505801 path = affected_file.LocalPath()
5802 if not _IsCPlusPlusFile(input_api, path):
5803 return False
5804
5805 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5806 if "/renderer/" in path:
5807 return True
5808
5809 # Blink's public/web API is only used/included by Renderer-only code. Note
5810 # that public/platform API may be used in non-Renderer processes (e.g. there
5811 # are some includes in code used by Utility, PDF, or Plugin processes).
5812 if "/blink/public/web/" in path:
5813 return True
5814
5815 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275816 return False
5817
Lukasz Anforowicz7016d05e2021-11-30 03:56:275818# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5819# by the Chromium Clang Plugin (which will be preferable because it will
5820# 1) report errors earlier - at compile-time and 2) cover more rules).
5821def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505822 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5823 errors = []
5824 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5825 # C++ comment.
5826 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5827 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5828 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5829 if raw_ptr_matcher.search(line):
5830 errors.append(
5831 output_api.PresubmitError(
5832 'Problem on {path}:{line} - '\
5833 'raw_ptr<T> should not be used in Renderer-only code '\
5834 '(as documented in the "Pointers to unprotected memory" '\
5835 'section in //base/memory/raw_ptr.md)'.format(
5836 path=f.LocalPath(), line=line_num)))
5837 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565838
5839
5840def CheckPythonShebang(input_api, output_api):
5841 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5842 system-wide python.
5843 """
5844 errors = []
5845 sources = lambda affected_file: input_api.FilterSourceFile(
5846 affected_file,
5847 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5848 r'third_party/blink/web_tests/external/') + input_api.
5849 DEFAULT_FILES_TO_SKIP),
5850 files_to_check=[r'.*\.py$'])
5851 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275852 for line_num, line in f.ChangedContents():
5853 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5854 errors.append(f.LocalPath())
5855 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565856
5857 result = []
5858 for file in errors:
5859 result.append(
5860 output_api.PresubmitError(
5861 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5862 file))
5863 return result