blob: 973955c9fbef54d0a4b7c36ab3f53306da0e3804 [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[\\/]',
John Chen288dee02022-04-28 17:37:061050 r'^tools[\\/]perf[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161051]
1052
Andrew Grieveb773bad2020-06-05 18:00:381053# These are not checked on the public chromium-presubmit trybot.
1054# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041055# checkouts.
agrievef32bcc72016-04-04 14:57:401056_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381057 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381058]
1059
1060
1061_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041062 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361063 'base/android/jni_generator/jni_generator.pydeps',
1064 'base/android/jni_generator/jni_registration_generator.pydeps',
Andrew Grieve4c4cede2020-11-20 22:09:361065 'build/android/apk_operations.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041066 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361067 'build/android/gyp/aar.pydeps',
1068 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271069 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361070 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381071 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361072 'build/android/gyp/bytecode_processor.pydeps',
Robbie McElrath360e54d2020-11-12 20:38:021073 'build/android/gyp/bytecode_rewriter.pydeps',
Mohamed Heikal6305bcc2021-03-15 15:34:221074 'build/android/gyp/check_flag_expectations.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111075 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361076 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361077 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361078 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111079 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041080 'build/android/gyp/create_app_bundle_apks.pydeps',
1081 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361082 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121083 'build/android/gyp/create_r_java.pydeps',
Mohamed Heikal8cd763a52021-02-01 23:32:091084 'build/android/gyp/create_r_txt.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221085 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001086 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361087 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421088 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041089 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361090 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361091 'build/android/gyp/filter_zip.pydeps',
Mohamed Heikal21e1994b2021-11-12 21:37:211092 'build/android/gyp/flatc_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361093 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361094 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361095 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581096 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361097 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141098 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261099 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve09457912021-04-27 15:22:471100 'build/android/gyp/java_google_api_keys.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011101 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041102 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361103 'build/android/gyp/lint.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361104 'build/android/gyp/merge_manifest.pydeps',
1105 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221106 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361107 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461108 'build/android/gyp/turbine.pydeps',
Mohamed Heikal246710c2021-06-14 15:34:301109 'build/android/gyp/unused_resources.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241110 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361111 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461112 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561113 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361114 'build/android/incremental_install/generate_android_manifest.pydeps',
1115 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041116 'build/android/resource_sizes.pydeps',
1117 'build/android/test_runner.pydeps',
1118 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361119 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361120 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321121 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271122 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1123 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Junbo Kedcd3a452021-03-19 17:55:041124 'chromecast/resource_sizes/chromecast_resource_sizes.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001125 'components/cronet/tools/generate_javadoc.pydeps',
1126 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381127 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001128 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381129 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041130 'testing/scripts/run_android_wpt.pydeps',
Peter Kotwicz3c339f32020-10-19 19:59:181131 'testing/scripts/run_isolated_script_test.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411132 'testing/merge_scripts/standard_isolated_script_merge.pydeps',
1133 'testing/merge_scripts/standard_gtest_merge.pydeps',
1134 'testing/merge_scripts/code_coverage/merge_results.pydeps',
1135 'testing/merge_scripts/code_coverage/merge_steps.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041136 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421137 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1138 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131139 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Canon Mukaif32f8f592021-04-23 18:56:501140 'third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps',
Stephanie Kimc94072c2022-03-22 22:31:411141 'third_party/blink/tools/blinkpy/web_tests/merge_results.pydeps',
1142 'third_party/blink/tools/merge_web_test_results.pydeps',
John Budorickbc3571aa2019-04-25 02:20:061143 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221144 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401145]
1146
wnwenbdc444e2016-05-25 13:44:151147
agrievef32bcc72016-04-04 14:57:401148_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1149
1150
Eric Boren6fd2b932018-01-25 15:05:081151# Bypass the AUTHORS check for these accounts.
1152_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591153 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451154 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591155 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521156 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Sven Zhengf7abd31d2021-08-09 19:06:231157 'wpt-autoroller', 'chrome-weblayer-builder',
Garrett Beaty4d4fcf62021-11-24 17:57:471158 'lacros-version-skew-roller', 'skylab-test-cros-roller',
Jieting Yang668bde92022-01-27 18:40:431159 'infra-try-recipes-tester', 'lacros-tracking-roller')
Eric Boren835d71f2018-09-07 21:09:041160 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271161 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041162 ) | set('%[email protected]' % s
Yulan Lineb0cfba2021-04-09 18:43:161163 for s in ('chromium-internal-autoroll',)
1164 ) | set('%[email protected]' % s
1165 for s in ('swarming-tasks',))
Eric Boren6fd2b932018-01-25 15:05:081166
Matt Stark6ef08872021-07-29 01:21:461167_INVALID_GRD_FILE_LINE = [
1168 (r'<file lang=.* path=.*', 'Path should come before lang in GRD files.')
1169]
Eric Boren6fd2b932018-01-25 15:05:081170
Daniel Bratell65b033262019-04-23 08:17:061171def _IsCPlusPlusFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501172 """Returns True if this file contains C++-like code (and not Python,
1173 Go, Java, MarkDown, ...)"""
Daniel Bratell65b033262019-04-23 08:17:061174
Sam Maiera6e76d72022-02-11 21:43:501175 ext = input_api.os_path.splitext(file_path)[1]
1176 # This list is compatible with CppChecker.IsCppFile but we should
1177 # consider adding ".c" to it. If we do that we can use this function
1178 # at more places in the code.
1179 return ext in (
1180 '.h',
1181 '.cc',
1182 '.cpp',
1183 '.m',
1184 '.mm',
1185 )
1186
Daniel Bratell65b033262019-04-23 08:17:061187
1188def _IsCPlusPlusHeaderFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501189 return input_api.os_path.splitext(file_path)[1] == ".h"
Daniel Bratell65b033262019-04-23 08:17:061190
1191
1192def _IsJavaFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501193 return input_api.os_path.splitext(file_path)[1] == ".java"
Daniel Bratell65b033262019-04-23 08:17:061194
1195
1196def _IsProtoFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501197 return input_api.os_path.splitext(file_path)[1] == ".proto"
Daniel Bratell65b033262019-04-23 08:17:061198
Mohamed Heikal5e5b7922020-10-29 18:57:591199
Erik Staabc734cd7a2021-11-23 03:11:521200def _IsXmlOrGrdFile(input_api, file_path):
Sam Maiera6e76d72022-02-11 21:43:501201 ext = input_api.os_path.splitext(file_path)[1]
1202 return ext in ('.grd', '.xml')
Erik Staabc734cd7a2021-11-23 03:11:521203
1204
Mohamed Heikal5e5b7922020-10-29 18:57:591205def CheckNoUpstreamDepsOnClank(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501206 """Prevent additions of dependencies from the upstream repo on //clank."""
1207 # clank can depend on clank
1208 if input_api.change.RepositoryRoot().endswith('clank'):
1209 return []
1210 build_file_patterns = [
1211 r'(.+/)?BUILD\.gn',
1212 r'.+\.gni',
1213 ]
1214 excluded_files = [r'build[/\\]config[/\\]android[/\\]config\.gni']
1215 bad_pattern = input_api.re.compile(r'^[^#]*//clank')
Mohamed Heikal5e5b7922020-10-29 18:57:591216
Sam Maiera6e76d72022-02-11 21:43:501217 error_message = 'Disallowed import on //clank in an upstream build file:'
Mohamed Heikal5e5b7922020-10-29 18:57:591218
Sam Maiera6e76d72022-02-11 21:43:501219 def FilterFile(affected_file):
1220 return input_api.FilterSourceFile(affected_file,
1221 files_to_check=build_file_patterns,
1222 files_to_skip=excluded_files)
Mohamed Heikal5e5b7922020-10-29 18:57:591223
Sam Maiera6e76d72022-02-11 21:43:501224 problems = []
1225 for f in input_api.AffectedSourceFiles(FilterFile):
1226 local_path = f.LocalPath()
1227 for line_number, line in f.ChangedContents():
1228 if (bad_pattern.search(line)):
1229 problems.append('%s:%d\n %s' %
1230 (local_path, line_number, line.strip()))
1231 if problems:
1232 return [output_api.PresubmitPromptOrNotify(error_message, problems)]
1233 else:
1234 return []
Mohamed Heikal5e5b7922020-10-29 18:57:591235
1236
Saagar Sanghavifceeaae2020-08-12 16:40:361237def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501238 """Attempts to prevent use of functions intended only for testing in
1239 non-testing code. For now this is just a best-effort implementation
1240 that ignores header files and may have some false positives. A
1241 better implementation would probably need a proper C++ parser.
1242 """
1243 # We only scan .cc files and the like, as the declaration of
1244 # for-testing functions in header files are hard to distinguish from
1245 # calls to such functions without a proper C++ parser.
1246 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191247
Sam Maiera6e76d72022-02-11 21:43:501248 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
1249 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' %
1250 base_function_pattern)
1251 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
1252 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
1253 exclusion_pattern = input_api.re.compile(
1254 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' %
1255 (base_function_pattern, base_function_pattern))
1256 # Avoid a false positive in this case, where the method name, the ::, and
1257 # the closing { are all on different lines due to line wrapping.
1258 # HelperClassForTesting::
1259 # HelperClassForTesting(
1260 # args)
1261 # : member(0) {}
1262 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191263
Sam Maiera6e76d72022-02-11 21:43:501264 def FilterFile(affected_file):
1265 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1266 input_api.DEFAULT_FILES_TO_SKIP)
1267 return input_api.FilterSourceFile(
1268 affected_file,
1269 files_to_check=file_inclusion_pattern,
1270 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191271
Sam Maiera6e76d72022-02-11 21:43:501272 problems = []
1273 for f in input_api.AffectedSourceFiles(FilterFile):
1274 local_path = f.LocalPath()
1275 in_method_defn = False
1276 for line_number, line in f.ChangedContents():
1277 if (inclusion_pattern.search(line)
1278 and not comment_pattern.search(line)
1279 and not exclusion_pattern.search(line)
1280 and not allowlist_pattern.search(line)
1281 and not in_method_defn):
1282 problems.append('%s:%d\n %s' %
1283 (local_path, line_number, line.strip()))
1284 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191285
Sam Maiera6e76d72022-02-11 21:43:501286 if problems:
1287 return [
1288 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1289 ]
1290 else:
1291 return []
[email protected]55459852011-08-10 15:17:191292
1293
Saagar Sanghavifceeaae2020-08-12 16:40:361294def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501295 """This is a simplified version of
1296 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
1297 """
1298 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1299 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1300 name_pattern = r'ForTest(s|ing)?'
1301 # Describes an occurrence of "ForTest*" inside a // comment.
1302 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
1303 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1304 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
1305 # Catch calls.
1306 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1307 # Ignore definitions. (Comments are ignored separately.)
1308 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
Vaclav Brozek7dbc28c2018-03-27 08:35:231309
Sam Maiera6e76d72022-02-11 21:43:501310 problems = []
1311 sources = lambda x: input_api.FilterSourceFile(
1312 x,
1313 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
1314 DEFAULT_FILES_TO_SKIP),
1315 files_to_check=[r'.*\.java$'])
1316 for f in input_api.AffectedFiles(include_deletes=False,
1317 file_filter=sources):
1318 local_path = f.LocalPath()
Vaclav Brozek7dbc28c2018-03-27 08:35:231319 is_inside_javadoc = False
Sam Maiera6e76d72022-02-11 21:43:501320 for line_number, line in f.ChangedContents():
1321 if is_inside_javadoc and javadoc_end_re.search(line):
1322 is_inside_javadoc = False
1323 if not is_inside_javadoc and javadoc_start_re.search(line):
1324 is_inside_javadoc = True
1325 if is_inside_javadoc:
1326 continue
1327 if (inclusion_re.search(line) and not comment_re.search(line)
1328 and not annotation_re.search(line)
1329 and not exclusion_re.search(line)):
1330 problems.append('%s:%d\n %s' %
1331 (local_path, line_number, line.strip()))
Vaclav Brozek7dbc28c2018-03-27 08:35:231332
Sam Maiera6e76d72022-02-11 21:43:501333 if problems:
1334 return [
1335 output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)
1336 ]
1337 else:
1338 return []
Vaclav Brozek7dbc28c2018-03-27 08:35:231339
1340
Saagar Sanghavifceeaae2020-08-12 16:40:361341def CheckNoIOStreamInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501342 """Checks to make sure no .h files include <iostream>."""
1343 files = []
1344 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1345 input_api.re.MULTILINE)
1346 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1347 if not f.LocalPath().endswith('.h'):
1348 continue
1349 contents = input_api.ReadFile(f)
1350 if pattern.search(contents):
1351 files.append(f)
[email protected]10689ca2011-09-02 02:31:541352
Sam Maiera6e76d72022-02-11 21:43:501353 if len(files):
1354 return [
1355 output_api.PresubmitError(
1356 'Do not #include <iostream> in header files, since it inserts static '
1357 'initialization into every file including the header. Instead, '
1358 '#include <ostream>. See http://crbug.com/94794', files)
1359 ]
1360 return []
1361
[email protected]10689ca2011-09-02 02:31:541362
Danil Chapovalov3518f362018-08-11 16:13:431363def _CheckNoStrCatRedefines(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501364 """Checks no windows headers with StrCat redefined are included directly."""
1365 files = []
1366 pattern_deny = input_api.re.compile(
1367 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1368 input_api.re.MULTILINE)
1369 pattern_allow = input_api.re.compile(
1370 r'^#include\s"base/win/windows_defines.inc"', input_api.re.MULTILINE)
1371 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1372 contents = input_api.ReadFile(f)
1373 if pattern_deny.search(
1374 contents) and not pattern_allow.search(contents):
1375 files.append(f.LocalPath())
Danil Chapovalov3518f362018-08-11 16:13:431376
Sam Maiera6e76d72022-02-11 21:43:501377 if len(files):
1378 return [
1379 output_api.PresubmitError(
1380 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1381 'directly since they pollute code with StrCat macro. Instead, '
1382 'include matching header from base/win. See http://crbug.com/856536',
1383 files)
1384 ]
1385 return []
Danil Chapovalov3518f362018-08-11 16:13:431386
[email protected]10689ca2011-09-02 02:31:541387
Saagar Sanghavifceeaae2020-08-12 16:40:361388def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501389 """Checks to make sure no source files use UNIT_TEST."""
1390 problems = []
1391 for f in input_api.AffectedFiles():
1392 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1393 continue
[email protected]72df4e782012-06-21 16:28:181394
Sam Maiera6e76d72022-02-11 21:43:501395 for line_num, line in f.ChangedContents():
1396 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
1397 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]72df4e782012-06-21 16:28:181398
Sam Maiera6e76d72022-02-11 21:43:501399 if not problems:
1400 return []
1401 return [
1402 output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1403 '\n'.join(problems))
1404 ]
1405
[email protected]72df4e782012-06-21 16:28:181406
Saagar Sanghavifceeaae2020-08-12 16:40:361407def CheckNoDISABLETypoInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501408 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
Dominic Battre033531052018-09-24 15:45:341409
Sam Maiera6e76d72022-02-11 21:43:501410 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1411 instead of DISABLED_. To filter false positives, reports are only generated
1412 if a corresponding MAYBE_ line exists.
1413 """
1414 problems = []
Dominic Battre033531052018-09-24 15:45:341415
Sam Maiera6e76d72022-02-11 21:43:501416 # The following two patterns are looked for in tandem - is a test labeled
1417 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1418 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1419 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
Dominic Battre033531052018-09-24 15:45:341420
Sam Maiera6e76d72022-02-11 21:43:501421 # This is for the case that a test is disabled on all platforms.
1422 full_disable_pattern = input_api.re.compile(
1423 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1424 input_api.re.MULTILINE)
Dominic Battre033531052018-09-24 15:45:341425
Sam Maiera6e76d72022-02-11 21:43:501426 for f in input_api.AffectedFiles(False):
1427 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1428 continue
Dominic Battre033531052018-09-24 15:45:341429
Sam Maiera6e76d72022-02-11 21:43:501430 # Search for MABYE_, DISABLE_ pairs.
1431 disable_lines = {} # Maps of test name to line number.
1432 maybe_lines = {}
1433 for line_num, line in f.ChangedContents():
1434 disable_match = disable_pattern.search(line)
1435 if disable_match:
1436 disable_lines[disable_match.group(1)] = line_num
1437 maybe_match = maybe_pattern.search(line)
1438 if maybe_match:
1439 maybe_lines[maybe_match.group(1)] = line_num
Dominic Battre033531052018-09-24 15:45:341440
Sam Maiera6e76d72022-02-11 21:43:501441 # Search for DISABLE_ occurrences within a TEST() macro.
1442 disable_tests = set(disable_lines.keys())
1443 maybe_tests = set(maybe_lines.keys())
1444 for test in disable_tests.intersection(maybe_tests):
1445 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
Dominic Battre033531052018-09-24 15:45:341446
Sam Maiera6e76d72022-02-11 21:43:501447 contents = input_api.ReadFile(f)
1448 full_disable_match = full_disable_pattern.search(contents)
1449 if full_disable_match:
1450 problems.append(' %s' % f.LocalPath())
Dominic Battre033531052018-09-24 15:45:341451
Sam Maiera6e76d72022-02-11 21:43:501452 if not problems:
1453 return []
1454 return [
1455 output_api.PresubmitPromptWarning(
1456 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1457 '\n'.join(problems))
1458 ]
1459
Dominic Battre033531052018-09-24 15:45:341460
Nina Satragnof7660532021-09-20 18:03:351461def CheckForgettingMAYBEInTests(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501462 """Checks to make sure tests disabled conditionally are not missing a
1463 corresponding MAYBE_ prefix.
1464 """
1465 # Expect at least a lowercase character in the test name. This helps rule out
1466 # false positives with macros wrapping the actual tests name.
1467 define_maybe_pattern = input_api.re.compile(
1468 r'^\#define MAYBE_(?P<test_name>\w*[a-z]\w*)')
Bruce Dawsonffc55292022-04-20 04:18:191469 # The test_maybe_pattern needs to handle all of these forms. The standard:
1470 # IN_PROC_TEST_F(SyncTest, MAYBE_Start) {
1471 # With a wrapper macro around the test name:
1472 # IN_PROC_TEST_F(SyncTest, E2E_ENABLED(MAYBE_Start)) {
1473 # And the odd-ball NACL_BROWSER_TEST_f format:
1474 # NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
1475 # The optional E2E_ENABLED-style is handled with (\w*\()?
1476 # The NACL_BROWSER_TEST_F pattern is handled by allowing a trailing comma or
1477 # trailing ')'.
1478 test_maybe_pattern = (
1479 r'^\s*\w*TEST[^(]*\(\s*\w+,\s*(\w*\()?MAYBE_{test_name}[\),]')
Sam Maiera6e76d72022-02-11 21:43:501480 suite_maybe_pattern = r'^\s*\w*TEST[^(]*\(\s*MAYBE_{test_name}[\),]'
1481 warnings = []
Nina Satragnof7660532021-09-20 18:03:351482
Sam Maiera6e76d72022-02-11 21:43:501483 # Read the entire files. We can't just read the affected lines, forgetting to
1484 # add MAYBE_ on a change would not show up otherwise.
1485 for f in input_api.AffectedFiles(False):
1486 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1487 continue
1488 contents = input_api.ReadFile(f)
1489 lines = contents.splitlines(True)
1490 current_position = 0
1491 warning_test_names = set()
1492 for line_num, line in enumerate(lines, start=1):
1493 current_position += len(line)
1494 maybe_match = define_maybe_pattern.search(line)
1495 if maybe_match:
1496 test_name = maybe_match.group('test_name')
1497 # Do not warn twice for the same test.
1498 if (test_name in warning_test_names):
1499 continue
1500 warning_test_names.add(test_name)
Nina Satragnof7660532021-09-20 18:03:351501
Sam Maiera6e76d72022-02-11 21:43:501502 # Attempt to find the corresponding MAYBE_ test or suite, starting from
1503 # the current position.
1504 test_match = input_api.re.compile(
1505 test_maybe_pattern.format(test_name=test_name),
1506 input_api.re.MULTILINE).search(contents, current_position)
1507 suite_match = input_api.re.compile(
1508 suite_maybe_pattern.format(test_name=test_name),
1509 input_api.re.MULTILINE).search(contents, current_position)
1510 if not test_match and not suite_match:
1511 warnings.append(
1512 output_api.PresubmitPromptWarning(
1513 '%s:%d found MAYBE_ defined without corresponding test %s'
1514 % (f.LocalPath(), line_num, test_name)))
1515 return warnings
1516
[email protected]72df4e782012-06-21 16:28:181517
Saagar Sanghavifceeaae2020-08-12 16:40:361518def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501519 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
1520 errors = []
1521 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
1522 input_api.re.MULTILINE)
1523 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1524 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1525 continue
1526 for lnum, line in f.ChangedContents():
1527 if input_api.re.search(pattern, line):
1528 errors.append(
1529 output_api.PresubmitError((
1530 '%s:%d: Use of DCHECK_IS_ON() must be written as "#if '
1531 + 'DCHECK_IS_ON()", not forgetting the parentheses.') %
1532 (f.LocalPath(), lnum)))
1533 return errors
danakj61c1aa22015-10-26 19:55:521534
1535
Weilun Shia487fad2020-10-28 00:10:341536# TODO(crbug/1138055): Reimplement CheckUmaHistogramChangesOnUpload check in a
1537# more reliable way. See
1538# https://chromium-review.googlesource.com/c/chromium/src/+/2500269
mcasasb7440c282015-02-04 14:52:191539
wnwenbdc444e2016-05-25 13:44:151540
Saagar Sanghavifceeaae2020-08-12 16:40:361541def CheckFlakyTestUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501542 """Check that FlakyTest annotation is our own instead of the android one"""
1543 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1544 files = []
1545 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1546 if f.LocalPath().endswith('Test.java'):
1547 if pattern.search(input_api.ReadFile(f)):
1548 files.append(f)
1549 if len(files):
1550 return [
1551 output_api.PresubmitError(
1552 'Use org.chromium.base.test.util.FlakyTest instead of '
1553 'android.test.FlakyTest', files)
1554 ]
1555 return []
mcasasb7440c282015-02-04 14:52:191556
wnwenbdc444e2016-05-25 13:44:151557
Saagar Sanghavifceeaae2020-08-12 16:40:361558def CheckNoDEPSGIT(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501559 """Make sure .DEPS.git is never modified manually."""
1560 if any(f.LocalPath().endswith('.DEPS.git')
1561 for f in input_api.AffectedFiles()):
1562 return [
1563 output_api.PresubmitError(
1564 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1565 'automated system based on what\'s in DEPS and your changes will be\n'
1566 'overwritten.\n'
1567 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1568 'get-the-code#Rolling_DEPS\n'
1569 'for more information')
1570 ]
1571 return []
[email protected]2a8ac9c2011-10-19 17:20:441572
1573
Saagar Sanghavifceeaae2020-08-12 16:40:361574def CheckValidHostsInDEPSOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501575 """Checks that DEPS file deps are from allowed_hosts."""
1576 # Run only if DEPS file has been modified to annoy fewer bystanders.
1577 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1578 return []
1579 # Outsource work to gclient verify
1580 try:
1581 gclient_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
1582 'third_party', 'depot_tools',
1583 'gclient.py')
1584 input_api.subprocess.check_output(
1585 [input_api.python_executable, gclient_path, 'verify'],
1586 stderr=input_api.subprocess.STDOUT)
1587 return []
1588 except input_api.subprocess.CalledProcessError as error:
1589 return [
1590 output_api.PresubmitError(
1591 'DEPS file must have only git dependencies.',
1592 long_text=error.output)
1593 ]
tandriief664692014-09-23 14:51:471594
1595
Mario Sanchez Prada2472cab2019-09-18 10:58:311596def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151597 ban_rule):
Sam Maiera6e76d72022-02-11 21:43:501598 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311599
Sam Maiera6e76d72022-02-11 21:43:501600 Returns an string composed of the name of the file, the line number where the
1601 match has been found and the additional text passed as |message| in case the
1602 target type name matches the text inside the line passed as parameter.
1603 """
1604 result = []
Peng Huang9c5949a02020-06-11 19:20:541605
Daniel Chenga44a1bcd2022-03-15 20:00:151606 # Ignore comments about banned types.
1607 if input_api.re.search(r"^ *//", line):
Sam Maiera6e76d72022-02-11 21:43:501608 return result
Daniel Chenga44a1bcd2022-03-15 20:00:151609 # A // nocheck comment will bypass this error.
1610 if line.endswith(" nocheck"):
Sam Maiera6e76d72022-02-11 21:43:501611 return result
1612
1613 matched = False
Daniel Chenga44a1bcd2022-03-15 20:00:151614 if ban_rule.pattern[0:1] == '/':
1615 regex = ban_rule.pattern[1:]
Sam Maiera6e76d72022-02-11 21:43:501616 if input_api.re.search(regex, line):
1617 matched = True
Daniel Chenga44a1bcd2022-03-15 20:00:151618 elif ban_rule.pattern in line:
Sam Maiera6e76d72022-02-11 21:43:501619 matched = True
1620
1621 if matched:
1622 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
Daniel Chenga44a1bcd2022-03-15 20:00:151623 for line in ban_rule.explanation:
1624 result.append(' %s' % line)
Sam Maiera6e76d72022-02-11 21:43:501625
danakjd18e8892020-12-17 17:42:011626 return result
Mario Sanchez Prada2472cab2019-09-18 10:58:311627
1628
Saagar Sanghavifceeaae2020-08-12 16:40:361629def CheckNoBannedFunctions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501630 """Make sure that banned functions are not used."""
1631 warnings = []
1632 errors = []
[email protected]127f18ec2012-06-16 05:05:591633
Sam Maiera6e76d72022-02-11 21:43:501634 def IsExcludedFile(affected_file, excluded_paths):
Daniel Chenga44a1bcd2022-03-15 20:00:151635 if not excluded_paths:
1636 return False
1637
Sam Maiera6e76d72022-02-11 21:43:501638 local_path = affected_file.LocalPath()
1639 for item in excluded_paths:
1640 if input_api.re.match(item, local_path):
1641 return True
1642 return False
wnwenbdc444e2016-05-25 13:44:151643
Sam Maiera6e76d72022-02-11 21:43:501644 def IsIosObjcFile(affected_file):
1645 local_path = affected_file.LocalPath()
1646 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m',
1647 '.h'):
1648 return False
1649 basename = input_api.os_path.basename(local_path)
1650 if 'ios' in basename.split('_'):
1651 return True
1652 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1653 if sep and 'ios' in local_path.split(sep):
1654 return True
1655 return False
Sylvain Defresnea8b73d252018-02-28 15:45:541656
Daniel Chenga44a1bcd2022-03-15 20:00:151657 def CheckForMatch(affected_file, line_num: int, line: str,
1658 ban_rule: BanRule):
1659 if IsExcludedFile(affected_file, ban_rule.excluded_paths):
1660 return
1661
Sam Maiera6e76d72022-02-11 21:43:501662 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
Daniel Chenga44a1bcd2022-03-15 20:00:151663 ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501664 if problems:
Daniel Chenga44a1bcd2022-03-15 20:00:151665 if ban_rule.treat_as_error is not None and ban_rule.treat_as_error:
Sam Maiera6e76d72022-02-11 21:43:501666 errors.extend(problems)
1667 else:
1668 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151669
Sam Maiera6e76d72022-02-11 21:43:501670 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1671 for f in input_api.AffectedFiles(file_filter=file_filter):
1672 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151673 for ban_rule in _BANNED_JAVA_FUNCTIONS:
1674 CheckForMatch(f, line_num, line, ban_rule)
Eric Stevensona9a980972017-09-23 00:04:411675
Sam Maiera6e76d72022-02-11 21:43:501676 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1677 for f in input_api.AffectedFiles(file_filter=file_filter):
1678 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151679 for ban_rule in _BANNED_OBJC_FUNCTIONS:
1680 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591681
Sam Maiera6e76d72022-02-11 21:43:501682 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
1683 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151684 for ban_rule in _BANNED_IOS_OBJC_FUNCTIONS:
1685 CheckForMatch(f, line_num, line, ban_rule)
Sylvain Defresnea8b73d252018-02-28 15:45:541686
Sam Maiera6e76d72022-02-11 21:43:501687 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1688 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1689 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151690 for ban_rule in _BANNED_IOS_EGTEST_FUNCTIONS:
1691 CheckForMatch(f, line_num, line, ban_rule)
Peter K. Lee6c03ccff2019-07-15 14:40:051692
Sam Maiera6e76d72022-02-11 21:43:501693 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1694 for f in input_api.AffectedFiles(file_filter=file_filter):
1695 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151696 for ban_rule in _BANNED_CPP_FUNCTIONS:
1697 CheckForMatch(f, line_num, line, ban_rule)
[email protected]127f18ec2012-06-16 05:05:591698
Daniel Cheng92c15e32022-03-16 17:48:221699 file_filter = lambda f: f.LocalPath().endswith(('.mojom'))
1700 for f in input_api.AffectedFiles(file_filter=file_filter):
1701 for line_num, line in f.ChangedContents():
1702 for ban_rule in _BANNED_MOJOM_PATTERNS:
1703 CheckForMatch(f, line_num, line, ban_rule)
1704
1705
Sam Maiera6e76d72022-02-11 21:43:501706 result = []
1707 if (warnings):
1708 result.append(
1709 output_api.PresubmitPromptWarning('Banned functions were used.\n' +
1710 '\n'.join(warnings)))
1711 if (errors):
1712 result.append(
1713 output_api.PresubmitError('Banned functions were used.\n' +
1714 '\n'.join(errors)))
1715 return result
[email protected]127f18ec2012-06-16 05:05:591716
1717
Michael Thiessen44457642020-02-06 00:24:151718def _CheckAndroidNoBannedImports(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501719 """Make sure that banned java imports are not used."""
1720 errors = []
Michael Thiessen44457642020-02-06 00:24:151721
Sam Maiera6e76d72022-02-11 21:43:501722 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1723 for f in input_api.AffectedFiles(file_filter=file_filter):
1724 for line_num, line in f.ChangedContents():
Daniel Chenga44a1bcd2022-03-15 20:00:151725 for ban_rule in _BANNED_JAVA_IMPORTS:
1726 # Consider merging this into the above function. There is no
1727 # real difference anymore other than helping with a little
1728 # bit of boilerplate text. Doing so means things like
1729 # `treat_as_error` will also be uniformly handled.
Sam Maiera6e76d72022-02-11 21:43:501730 problems = _GetMessageForMatchingType(input_api, f, line_num,
Daniel Chenga44a1bcd2022-03-15 20:00:151731 line, ban_rule)
Sam Maiera6e76d72022-02-11 21:43:501732 if problems:
1733 errors.extend(problems)
1734 result = []
1735 if (errors):
1736 result.append(
1737 output_api.PresubmitError('Banned imports were used.\n' +
1738 '\n'.join(errors)))
1739 return result
Michael Thiessen44457642020-02-06 00:24:151740
1741
Saagar Sanghavifceeaae2020-08-12 16:40:361742def CheckNoPragmaOnce(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501743 """Make sure that banned functions are not used."""
1744 files = []
1745 pattern = input_api.re.compile(r'^#pragma\s+once', input_api.re.MULTILINE)
1746 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1747 if not f.LocalPath().endswith('.h'):
1748 continue
1749 contents = input_api.ReadFile(f)
1750 if pattern.search(contents):
1751 files.append(f)
[email protected]6c063c62012-07-11 19:11:061752
Sam Maiera6e76d72022-02-11 21:43:501753 if files:
1754 return [
1755 output_api.PresubmitError(
1756 'Do not use #pragma once in header files.\n'
1757 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1758 files)
1759 ]
1760 return []
[email protected]6c063c62012-07-11 19:11:061761
[email protected]127f18ec2012-06-16 05:05:591762
Saagar Sanghavifceeaae2020-08-12 16:40:361763def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501764 """Checks to make sure we don't introduce use of foo ? true : false."""
1765 problems = []
1766 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1767 for f in input_api.AffectedFiles():
1768 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1769 continue
[email protected]e7479052012-09-19 00:26:121770
Sam Maiera6e76d72022-02-11 21:43:501771 for line_num, line in f.ChangedContents():
1772 if pattern.match(line):
1773 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121774
Sam Maiera6e76d72022-02-11 21:43:501775 if not problems:
1776 return []
1777 return [
1778 output_api.PresubmitPromptWarning(
1779 'Please consider avoiding the "? true : false" pattern if possible.\n'
1780 + '\n'.join(problems))
1781 ]
[email protected]e7479052012-09-19 00:26:121782
1783
Saagar Sanghavifceeaae2020-08-12 16:40:361784def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501785 """Runs checkdeps on #include and import statements added in this
1786 change. Breaking - rules is an error, breaking ! rules is a
1787 warning.
1788 """
1789 # Return early if no relevant file types were modified.
1790 for f in input_api.AffectedFiles():
1791 path = f.LocalPath()
1792 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1793 or _IsJavaFile(input_api, path)):
1794 break
[email protected]55f9f382012-07-31 11:02:181795 else:
Sam Maiera6e76d72022-02-11 21:43:501796 return []
rhalavati08acd232017-04-03 07:23:281797
Sam Maiera6e76d72022-02-11 21:43:501798 import sys
1799 # We need to wait until we have an input_api object and use this
1800 # roundabout construct to import checkdeps because this file is
1801 # eval-ed and thus doesn't have __file__.
1802 original_sys_path = sys.path
1803 try:
1804 sys.path = sys.path + [
1805 input_api.os_path.join(input_api.PresubmitLocalPath(),
1806 'buildtools', 'checkdeps')
1807 ]
1808 import checkdeps
1809 from rules import Rule
1810 finally:
1811 # Restore sys.path to what it was before.
1812 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181813
Sam Maiera6e76d72022-02-11 21:43:501814 added_includes = []
1815 added_imports = []
1816 added_java_imports = []
1817 for f in input_api.AffectedFiles():
1818 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1819 changed_lines = [line for _, line in f.ChangedContents()]
1820 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1821 elif _IsProtoFile(input_api, f.LocalPath()):
1822 changed_lines = [line for _, line in f.ChangedContents()]
1823 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1824 elif _IsJavaFile(input_api, f.LocalPath()):
1825 changed_lines = [line for _, line in f.ChangedContents()]
1826 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241827
Sam Maiera6e76d72022-02-11 21:43:501828 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1829
1830 error_descriptions = []
1831 warning_descriptions = []
1832 error_subjects = set()
1833 warning_subjects = set()
1834
1835 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1836 added_includes):
1837 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1838 description_with_path = '%s\n %s' % (path, rule_description)
1839 if rule_type == Rule.DISALLOW:
1840 error_descriptions.append(description_with_path)
1841 error_subjects.add("#includes")
1842 else:
1843 warning_descriptions.append(description_with_path)
1844 warning_subjects.add("#includes")
1845
1846 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1847 added_imports):
1848 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1849 description_with_path = '%s\n %s' % (path, rule_description)
1850 if rule_type == Rule.DISALLOW:
1851 error_descriptions.append(description_with_path)
1852 error_subjects.add("imports")
1853 else:
1854 warning_descriptions.append(description_with_path)
1855 warning_subjects.add("imports")
1856
1857 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1858 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1859 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1860 description_with_path = '%s\n %s' % (path, rule_description)
1861 if rule_type == Rule.DISALLOW:
1862 error_descriptions.append(description_with_path)
1863 error_subjects.add("imports")
1864 else:
1865 warning_descriptions.append(description_with_path)
1866 warning_subjects.add("imports")
1867
1868 results = []
1869 if error_descriptions:
1870 results.append(
1871 output_api.PresubmitError(
1872 'You added one or more %s that violate checkdeps rules.' %
1873 " and ".join(error_subjects), error_descriptions))
1874 if warning_descriptions:
1875 results.append(
1876 output_api.PresubmitPromptOrNotify(
1877 'You added one or more %s of files that are temporarily\n'
1878 'allowed but being removed. Can you avoid introducing the\n'
1879 '%s? See relevant DEPS file(s) for details and contacts.' %
1880 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1881 warning_descriptions))
1882 return results
[email protected]55f9f382012-07-31 11:02:181883
1884
Saagar Sanghavifceeaae2020-08-12 16:40:361885def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501886 """Check that all files have their permissions properly set."""
1887 if input_api.platform == 'win32':
1888 return []
1889 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1890 'tools', 'checkperms',
1891 'checkperms.py')
1892 args = [
1893 input_api.python_executable, checkperms_tool, '--root',
1894 input_api.change.RepositoryRoot()
1895 ]
1896 with input_api.CreateTemporaryFile() as file_list:
1897 for f in input_api.AffectedFiles():
1898 # checkperms.py file/directory arguments must be relative to the
1899 # repository.
1900 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1901 file_list.close()
1902 args += ['--file-list', file_list.name]
1903 try:
1904 input_api.subprocess.check_output(args)
1905 return []
1906 except input_api.subprocess.CalledProcessError as error:
1907 return [
1908 output_api.PresubmitError('checkperms.py failed:',
1909 long_text=error.output.decode(
1910 'utf-8', 'ignore'))
1911 ]
[email protected]fbcafe5a2012-08-08 15:31:221912
1913
Saagar Sanghavifceeaae2020-08-12 16:40:361914def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501915 """Makes sure we don't include ui/aura/window_property.h
1916 in header files.
1917 """
1918 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1919 errors = []
1920 for f in input_api.AffectedFiles():
1921 if not f.LocalPath().endswith('.h'):
1922 continue
1923 for line_num, line in f.ChangedContents():
1924 if pattern.match(line):
1925 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491926
Sam Maiera6e76d72022-02-11 21:43:501927 results = []
1928 if errors:
1929 results.append(
1930 output_api.PresubmitError(
1931 'Header files should not include ui/aura/window_property.h',
1932 errors))
1933 return results
[email protected]c8278b32012-10-30 20:35:491934
1935
Omer Katzcc77ea92021-04-26 10:23:281936def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501937 """Makes sure we don't include any headers from
1938 third_party/blink/renderer/platform/heap/impl or
1939 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1940 third_party/blink/renderer/platform/heap
1941 """
1942 impl_pattern = input_api.re.compile(
1943 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1944 v8_wrapper_pattern = input_api.re.compile(
1945 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1946 )
1947 file_filter = lambda f: not input_api.re.match(
1948 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1949 f.LocalPath())
1950 errors = []
Omer Katzcc77ea92021-04-26 10:23:281951
Sam Maiera6e76d72022-02-11 21:43:501952 for f in input_api.AffectedFiles(file_filter=file_filter):
1953 for line_num, line in f.ChangedContents():
1954 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1955 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281956
Sam Maiera6e76d72022-02-11 21:43:501957 results = []
1958 if errors:
1959 results.append(
1960 output_api.PresubmitError(
1961 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1962 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1963 'relevant counterparts from third_party/blink/renderer/platform/heap',
1964 errors))
1965 return results
Omer Katzcc77ea92021-04-26 10:23:281966
1967
[email protected]70ca77752012-11-20 03:45:031968def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501969 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1970 errors = []
1971 for line_num, line in f.ChangedContents():
1972 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1973 # First-level headers in markdown look a lot like version control
1974 # conflict markers. http://daringfireball.net/projects/markdown/basics
1975 continue
1976 if pattern.match(line):
1977 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1978 return errors
[email protected]70ca77752012-11-20 03:45:031979
1980
Saagar Sanghavifceeaae2020-08-12 16:40:361981def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501982 """Usually this is not intentional and will cause a compile failure."""
1983 errors = []
1984 for f in input_api.AffectedFiles():
1985 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031986
Sam Maiera6e76d72022-02-11 21:43:501987 results = []
1988 if errors:
1989 results.append(
1990 output_api.PresubmitError(
1991 'Version control conflict markers found, please resolve.',
1992 errors))
1993 return results
[email protected]70ca77752012-11-20 03:45:031994
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201995
Saagar Sanghavifceeaae2020-08-12 16:40:361996def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501997 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1998 errors = []
1999 for f in input_api.AffectedFiles():
2000 for line_num, line in f.ChangedContents():
2001 if pattern.search(line):
2002 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162003
Sam Maiera6e76d72022-02-11 21:43:502004 results = []
2005 if errors:
2006 results.append(
2007 output_api.PresubmitPromptWarning(
2008 'Found Google support URL addressed by answer number. Please replace '
2009 'with a p= identifier instead. See crbug.com/679462\n',
2010 errors))
2011 return results
estadee17314a02017-01-12 16:22:162012
[email protected]70ca77752012-11-20 03:45:032013
Saagar Sanghavifceeaae2020-08-12 16:40:362014def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502015 def FilterFile(affected_file):
2016 """Filter function for use with input_api.AffectedSourceFiles,
2017 below. This filters out everything except non-test files from
2018 top-level directories that generally speaking should not hard-code
2019 service URLs (e.g. src/android_webview/, src/content/ and others).
2020 """
2021 return input_api.FilterSourceFile(
2022 affected_file,
2023 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2024 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2025 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442026
Sam Maiera6e76d72022-02-11 21:43:502027 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2028 '\.(com|net)[^"]*"')
2029 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2030 pattern = input_api.re.compile(base_pattern)
2031 problems = [] # items are (filename, line_number, line)
2032 for f in input_api.AffectedSourceFiles(FilterFile):
2033 for line_num, line in f.ChangedContents():
2034 if not comment_pattern.search(line) and pattern.search(line):
2035 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442036
Sam Maiera6e76d72022-02-11 21:43:502037 if problems:
2038 return [
2039 output_api.PresubmitPromptOrNotify(
2040 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2041 'Are you sure this is correct?', [
2042 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2043 for problem in problems
2044 ])
2045 ]
2046 else:
2047 return []
[email protected]06e6d0ff2012-12-11 01:36:442048
2049
Saagar Sanghavifceeaae2020-08-12 16:40:362050def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502051 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292052
Sam Maiera6e76d72022-02-11 21:43:502053 def FileFilter(affected_file):
2054 """Includes directories known to be Chrome OS only."""
2055 return input_api.FilterSourceFile(
2056 affected_file,
2057 files_to_check=(
2058 '^ash/',
2059 '^chromeos/', # Top-level src/chromeos.
2060 '.*/chromeos/', # Any path component.
2061 '^components/arc',
2062 '^components/exo'),
2063 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292064
Sam Maiera6e76d72022-02-11 21:43:502065 prefs = []
2066 priority_prefs = []
2067 for f in input_api.AffectedFiles(file_filter=FileFilter):
2068 for line_num, line in f.ChangedContents():
2069 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2070 line):
2071 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2072 prefs.append(' %s' % line)
2073 if input_api.re.search(
2074 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2075 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2076 priority_prefs.append(' %s' % line)
2077
2078 results = []
2079 if (prefs):
2080 results.append(
2081 output_api.PresubmitPromptWarning(
2082 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2083 'by browser sync settings. If these prefs should be controlled by OS '
2084 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2085 '\n'.join(prefs)))
2086 if (priority_prefs):
2087 results.append(
2088 output_api.PresubmitPromptWarning(
2089 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2090 'controlled by browser sync settings. If these prefs should be '
2091 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2092 'instead.\n' + '\n'.join(prefs)))
2093 return results
James Cook6b6597c2019-11-06 22:05:292094
2095
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492096# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362097def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502098 """Makes sure there are no abbreviations in the name of PNG files.
2099 The native_client_sdk directory is excluded because it has auto-generated PNG
2100 files for documentation.
2101 """
2102 errors = []
2103 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2104 files_to_skip = [r'^native_client_sdk[\\/]']
2105 file_filter = lambda f: input_api.FilterSourceFile(
2106 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2107 for f in input_api.AffectedFiles(include_deletes=False,
2108 file_filter=file_filter):
2109 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272110
Sam Maiera6e76d72022-02-11 21:43:502111 results = []
2112 if errors:
2113 results.append(
2114 output_api.PresubmitError(
2115 'The name of PNG files should not have abbreviations. \n'
2116 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2117 'Contact [email protected] if you have questions.', errors))
2118 return results
[email protected]d2530012013-01-25 16:39:272119
2120
Daniel Cheng4dcdb6b2017-04-13 08:30:172121def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502122 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172123
Sam Maiera6e76d72022-02-11 21:43:502124 Args:
2125 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2126 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172127 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502128 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172129 if rule.startswith('+') or rule.startswith('!')
2130 ])
Sam Maiera6e76d72022-02-11 21:43:502131 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2132 add_rules.update([
2133 rule[1:] for rule in rules
2134 if rule.startswith('+') or rule.startswith('!')
2135 ])
2136 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172137
2138
2139def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502140 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172141
Sam Maiera6e76d72022-02-11 21:43:502142 # Stubs for handling special syntax in the root DEPS file.
2143 class _VarImpl:
2144 def __init__(self, local_scope):
2145 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172146
Sam Maiera6e76d72022-02-11 21:43:502147 def Lookup(self, var_name):
2148 """Implements the Var syntax."""
2149 try:
2150 return self._local_scope['vars'][var_name]
2151 except KeyError:
2152 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172153
Sam Maiera6e76d72022-02-11 21:43:502154 local_scope = {}
2155 global_scope = {
2156 'Var': _VarImpl(local_scope).Lookup,
2157 'Str': str,
2158 }
Dirk Pranke1b9e06382021-05-14 01:16:222159
Sam Maiera6e76d72022-02-11 21:43:502160 exec(contents, global_scope, local_scope)
2161 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172162
2163
2164def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502165 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2166 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412167
Sam Maiera6e76d72022-02-11 21:43:502168 For a directory (rather than a specific filename) we fake a path to
2169 a specific filename by adding /DEPS. This is chosen as a file that
2170 will seldom or never be subject to per-file include_rules.
2171 """
2172 # We ignore deps entries on auto-generated directories.
2173 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082174
Sam Maiera6e76d72022-02-11 21:43:502175 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2176 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172177
Sam Maiera6e76d72022-02-11 21:43:502178 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172179
Sam Maiera6e76d72022-02-11 21:43:502180 results = set()
2181 for added_dep in added_deps:
2182 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2183 continue
2184 # Assume that a rule that ends in .h is a rule for a specific file.
2185 if added_dep.endswith('.h'):
2186 results.add(added_dep)
2187 else:
2188 results.add(os_path.join(added_dep, 'DEPS'))
2189 return results
[email protected]f32e2d1e2013-07-26 21:39:082190
2191
Saagar Sanghavifceeaae2020-08-12 16:40:362192def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502193 """When a dependency prefixed with + is added to a DEPS file, we
2194 want to make sure that the change is reviewed by an OWNER of the
2195 target file or directory, to avoid layering violations from being
2196 introduced. This check verifies that this happens.
2197 """
2198 # We rely on Gerrit's code-owners to check approvals.
2199 # input_api.gerrit is always set for Chromium, but other projects
2200 # might not use Gerrit.
2201 if not input_api.gerrit:
2202 return []
2203 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2204 input_api.change.issue)):
2205 # Skip OWNERS check when Owners-Override label is approved. This is intended
2206 # for global owners, trusted bots, and on-call sheriffs. Review is still
2207 # required for these changes.
2208 return []
Edward Lesmes6fba51082021-01-20 04:20:232209
Sam Maiera6e76d72022-02-11 21:43:502210 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242211
Sam Maiera6e76d72022-02-11 21:43:502212 file_filter = lambda f: not input_api.re.match(
2213 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2214 for f in input_api.AffectedFiles(include_deletes=False,
2215 file_filter=file_filter):
2216 filename = input_api.os_path.basename(f.LocalPath())
2217 if filename == 'DEPS':
2218 virtual_depended_on_files.update(
2219 _CalculateAddedDeps(input_api.os_path,
2220 '\n'.join(f.OldContents()),
2221 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552222
Sam Maiera6e76d72022-02-11 21:43:502223 if not virtual_depended_on_files:
2224 return []
[email protected]e871964c2013-05-13 14:14:552225
Sam Maiera6e76d72022-02-11 21:43:502226 if input_api.is_committing:
2227 if input_api.tbr:
2228 return [
2229 output_api.PresubmitNotifyResult(
2230 '--tbr was specified, skipping OWNERS check for DEPS additions'
2231 )
2232 ]
2233 if input_api.dry_run:
2234 return [
2235 output_api.PresubmitNotifyResult(
2236 'This is a dry run, skipping OWNERS check for DEPS additions'
2237 )
2238 ]
2239 if not input_api.change.issue:
2240 return [
2241 output_api.PresubmitError(
2242 "DEPS approval by OWNERS check failed: this change has "
2243 "no change number, so we can't check it for approvals.")
2244 ]
2245 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412246 else:
Sam Maiera6e76d72022-02-11 21:43:502247 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552248
Sam Maiera6e76d72022-02-11 21:43:502249 owner_email, reviewers = (
2250 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2251 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552252
Sam Maiera6e76d72022-02-11 21:43:502253 owner_email = owner_email or input_api.change.author_email
2254
2255 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2256 virtual_depended_on_files, reviewers.union([owner_email]), [])
2257 missing_files = [
2258 f for f in virtual_depended_on_files
2259 if approval_status[f] != input_api.owners_client.APPROVED
2260 ]
2261
2262 # We strip the /DEPS part that was added by
2263 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2264 # directory.
2265 def StripDeps(path):
2266 start_deps = path.rfind('/DEPS')
2267 if start_deps != -1:
2268 return path[:start_deps]
2269 else:
2270 return path
2271
2272 unapproved_dependencies = [
2273 "'+%s'," % StripDeps(path) for path in missing_files
2274 ]
2275
2276 if unapproved_dependencies:
2277 output_list = [
2278 output(
2279 'You need LGTM from owners of depends-on paths in DEPS that were '
2280 'modified in this CL:\n %s' %
2281 '\n '.join(sorted(unapproved_dependencies)))
2282 ]
2283 suggested_owners = input_api.owners_client.SuggestOwners(
2284 missing_files, exclude=[owner_email])
2285 output_list.append(
2286 output('Suggested missing target path OWNERS:\n %s' %
2287 '\n '.join(suggested_owners or [])))
2288 return output_list
2289
2290 return []
[email protected]e871964c2013-05-13 14:14:552291
2292
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492293# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362294def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502295 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2296 files_to_skip = (
2297 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2298 input_api.DEFAULT_FILES_TO_SKIP + (
2299 r"^base[\\/]logging\.h$",
2300 r"^base[\\/]logging\.cc$",
2301 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2302 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2303 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2304 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2305 r"startup_browser_creator\.cc$",
2306 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2307 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2308 r"diagnostics_writer\.cc$",
2309 r"^chrome[\\/]chrome_cleaner[\\/].*",
2310 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2311 r"dll_hash_main\.cc$",
2312 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2313 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502314 r"^components[\\/]browser_watcher[\\/]"
2315 r"dump_stability_report_main_win.cc$",
2316 r"^components[\\/]media_control[\\/]renderer[\\/]"
2317 r"media_playback_options\.cc$",
2318 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2319 r"overlay_strategy_underlay_cast\.cc$",
2320 r"^components[\\/]zucchini[\\/].*",
2321 # TODO(peter): Remove exception. https://crbug.com/534537
2322 r"^content[\\/]browser[\\/]notifications[\\/]"
2323 r"notification_event_dispatcher_impl\.cc$",
2324 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2325 r"gl_helper_benchmark\.cc$",
2326 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2327 r"^courgette[\\/]courgette_tool\.cc$",
2328 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2329 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2330 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2331 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2332 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2333 r"^ipc[\\/]ipc_logging\.cc$",
2334 r"^native_client_sdk[\\/]",
2335 r"^remoting[\\/]base[\\/]logging\.h$",
2336 r"^remoting[\\/]host[\\/].*",
2337 r"^sandbox[\\/]linux[\\/].*",
2338 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2339 r"dump_file_system.cc$",
2340 r"^tools[\\/]",
2341 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2342 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2343 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2344 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2345 r"xwmstartupcheck\.cc$"))
2346 source_file_filter = lambda x: input_api.FilterSourceFile(
2347 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402348
Sam Maiera6e76d72022-02-11 21:43:502349 log_info = set([])
2350 printf = set([])
[email protected]85218562013-11-22 07:41:402351
Sam Maiera6e76d72022-02-11 21:43:502352 for f in input_api.AffectedSourceFiles(source_file_filter):
2353 for _, line in f.ChangedContents():
2354 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2355 log_info.add(f.LocalPath())
2356 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2357 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372358
Sam Maiera6e76d72022-02-11 21:43:502359 if input_api.re.search(r"\bprintf\(", line):
2360 printf.add(f.LocalPath())
2361 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2362 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402363
Sam Maiera6e76d72022-02-11 21:43:502364 if log_info:
2365 return [
2366 output_api.PresubmitError(
2367 'These files spam the console log with LOG(INFO):',
2368 items=log_info)
2369 ]
2370 if printf:
2371 return [
2372 output_api.PresubmitError(
2373 'These files spam the console log with printf/fprintf:',
2374 items=printf)
2375 ]
2376 return []
[email protected]85218562013-11-22 07:41:402377
2378
Saagar Sanghavifceeaae2020-08-12 16:40:362379def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502380 """These types are all expected to hold locks while in scope and
2381 so should never be anonymous (which causes them to be immediately
2382 destroyed)."""
2383 they_who_must_be_named = [
2384 'base::AutoLock',
2385 'base::AutoReset',
2386 'base::AutoUnlock',
2387 'SkAutoAlphaRestore',
2388 'SkAutoBitmapShaderInstall',
2389 'SkAutoBlitterChoose',
2390 'SkAutoBounderCommit',
2391 'SkAutoCallProc',
2392 'SkAutoCanvasRestore',
2393 'SkAutoCommentBlock',
2394 'SkAutoDescriptor',
2395 'SkAutoDisableDirectionCheck',
2396 'SkAutoDisableOvalCheck',
2397 'SkAutoFree',
2398 'SkAutoGlyphCache',
2399 'SkAutoHDC',
2400 'SkAutoLockColors',
2401 'SkAutoLockPixels',
2402 'SkAutoMalloc',
2403 'SkAutoMaskFreeImage',
2404 'SkAutoMutexAcquire',
2405 'SkAutoPathBoundsUpdate',
2406 'SkAutoPDFRelease',
2407 'SkAutoRasterClipValidate',
2408 'SkAutoRef',
2409 'SkAutoTime',
2410 'SkAutoTrace',
2411 'SkAutoUnref',
2412 ]
2413 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2414 # bad: base::AutoLock(lock.get());
2415 # not bad: base::AutoLock lock(lock.get());
2416 bad_pattern = input_api.re.compile(anonymous)
2417 # good: new base::AutoLock(lock.get())
2418 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2419 errors = []
[email protected]49aa76a2013-12-04 06:59:162420
Sam Maiera6e76d72022-02-11 21:43:502421 for f in input_api.AffectedFiles():
2422 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2423 continue
2424 for linenum, line in f.ChangedContents():
2425 if bad_pattern.search(line) and not good_pattern.search(line):
2426 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162427
Sam Maiera6e76d72022-02-11 21:43:502428 if errors:
2429 return [
2430 output_api.PresubmitError(
2431 'These lines create anonymous variables that need to be named:',
2432 items=errors)
2433 ]
2434 return []
[email protected]49aa76a2013-12-04 06:59:162435
2436
Saagar Sanghavifceeaae2020-08-12 16:40:362437def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502438 # Returns whether |template_str| is of the form <T, U...> for some types T
2439 # and U. Assumes that |template_str| is already in the form <...>.
2440 def HasMoreThanOneArg(template_str):
2441 # Level of <...> nesting.
2442 nesting = 0
2443 for c in template_str:
2444 if c == '<':
2445 nesting += 1
2446 elif c == '>':
2447 nesting -= 1
2448 elif c == ',' and nesting == 1:
2449 return True
2450 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532451
Sam Maiera6e76d72022-02-11 21:43:502452 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2453 sources = lambda affected_file: input_api.FilterSourceFile(
2454 affected_file,
2455 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2456 DEFAULT_FILES_TO_SKIP),
2457 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552458
Sam Maiera6e76d72022-02-11 21:43:502459 # Pattern to capture a single "<...>" block of template arguments. It can
2460 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2461 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2462 # latter would likely require counting that < and > match, which is not
2463 # expressible in regular languages. Should the need arise, one can introduce
2464 # limited counting (matching up to a total number of nesting depth), which
2465 # should cover all practical cases for already a low nesting limit.
2466 template_arg_pattern = (
2467 r'<[^>]*' # Opening block of <.
2468 r'>([^<]*>)?') # Closing block of >.
2469 # Prefix expressing that whatever follows is not already inside a <...>
2470 # block.
2471 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2472 null_construct_pattern = input_api.re.compile(
2473 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2474 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552475
Sam Maiera6e76d72022-02-11 21:43:502476 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2477 template_arg_no_array_pattern = (
2478 r'<[^>]*[^]]' # Opening block of <.
2479 r'>([^(<]*[^]]>)?') # Closing block of >.
2480 # Prefix saying that what follows is the start of an expression.
2481 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2482 # Suffix saying that what follows are call parentheses with a non-empty list
2483 # of arguments.
2484 nonempty_arg_list_pattern = r'\(([^)]|$)'
2485 # Put the template argument into a capture group for deeper examination later.
2486 return_construct_pattern = input_api.re.compile(
2487 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2488 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552489
Sam Maiera6e76d72022-02-11 21:43:502490 problems_constructor = []
2491 problems_nullptr = []
2492 for f in input_api.AffectedSourceFiles(sources):
2493 for line_number, line in f.ChangedContents():
2494 # Disallow:
2495 # return std::unique_ptr<T>(foo);
2496 # bar = std::unique_ptr<T>(foo);
2497 # But allow:
2498 # return std::unique_ptr<T[]>(foo);
2499 # bar = std::unique_ptr<T[]>(foo);
2500 # And also allow cases when the second template argument is present. Those
2501 # cases cannot be handled by std::make_unique:
2502 # return std::unique_ptr<T, U>(foo);
2503 # bar = std::unique_ptr<T, U>(foo);
2504 local_path = f.LocalPath()
2505 return_construct_result = return_construct_pattern.search(line)
2506 if return_construct_result and not HasMoreThanOneArg(
2507 return_construct_result.group('template_arg')):
2508 problems_constructor.append(
2509 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2510 # Disallow:
2511 # std::unique_ptr<T>()
2512 if null_construct_pattern.search(line):
2513 problems_nullptr.append(
2514 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052515
Sam Maiera6e76d72022-02-11 21:43:502516 errors = []
2517 if problems_nullptr:
2518 errors.append(
2519 output_api.PresubmitPromptWarning(
2520 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2521 problems_nullptr))
2522 if problems_constructor:
2523 errors.append(
2524 output_api.PresubmitError(
2525 'The following files use explicit std::unique_ptr constructor. '
2526 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2527 'std::make_unique is not an option.', problems_constructor))
2528 return errors
Peter Kasting4844e46e2018-02-23 07:27:102529
2530
Saagar Sanghavifceeaae2020-08-12 16:40:362531def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502532 """Checks if any new user action has been added."""
2533 if any('actions.xml' == input_api.os_path.basename(f)
2534 for f in input_api.LocalPaths()):
2535 # If actions.xml is already included in the changelist, the PRESUBMIT
2536 # for actions.xml will do a more complete presubmit check.
2537 return []
2538
2539 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2540 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2541 input_api.DEFAULT_FILES_TO_SKIP)
2542 file_filter = lambda f: input_api.FilterSourceFile(
2543 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2544
2545 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2546 current_actions = None
2547 for f in input_api.AffectedFiles(file_filter=file_filter):
2548 for line_num, line in f.ChangedContents():
2549 match = input_api.re.search(action_re, line)
2550 if match:
2551 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2552 # loaded only once.
2553 if not current_actions:
2554 with open(
2555 'tools/metrics/actions/actions.xml') as actions_f:
2556 current_actions = actions_f.read()
2557 # Search for the matched user action name in |current_actions|.
2558 for action_name in match.groups():
2559 action = 'name="{0}"'.format(action_name)
2560 if action not in current_actions:
2561 return [
2562 output_api.PresubmitPromptWarning(
2563 'File %s line %d: %s is missing in '
2564 'tools/metrics/actions/actions.xml. Please run '
2565 'tools/metrics/actions/extract_actions.py to update.'
2566 % (f.LocalPath(), line_num, action_name))
2567 ]
[email protected]999261d2014-03-03 20:08:082568 return []
2569
[email protected]999261d2014-03-03 20:08:082570
Daniel Cheng13ca61a882017-08-25 15:11:252571def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502572 import sys
2573 sys.path = sys.path + [
2574 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2575 'json_comment_eater')
2576 ]
2577 import json_comment_eater
2578 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252579
2580
[email protected]99171a92014-06-03 08:44:472581def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172582 try:
Sam Maiera6e76d72022-02-11 21:43:502583 contents = input_api.ReadFile(filename)
2584 if eat_comments:
2585 json_comment_eater = _ImportJSONCommentEater(input_api)
2586 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172587
Sam Maiera6e76d72022-02-11 21:43:502588 input_api.json.loads(contents)
2589 except ValueError as e:
2590 return e
Andrew Grieve4deedb12022-02-03 21:34:502591 return None
2592
2593
Sam Maiera6e76d72022-02-11 21:43:502594def _GetIDLParseError(input_api, filename):
2595 try:
2596 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282597 for i, char in enumerate(contents):
2598 if not char.isascii():
2599 return ('Non-ascii character "%s" (ord %d) found at offset %d.'
2600 % (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502601 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2602 'tools', 'json_schema_compiler',
2603 'idl_schema.py')
2604 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282605 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502606 stdin=input_api.subprocess.PIPE,
2607 stdout=input_api.subprocess.PIPE,
2608 stderr=input_api.subprocess.PIPE,
2609 universal_newlines=True)
2610 (_, error) = process.communicate(input=contents)
2611 return error or None
2612 except ValueError as e:
2613 return e
agrievef32bcc72016-04-04 14:57:402614
agrievef32bcc72016-04-04 14:57:402615
Sam Maiera6e76d72022-02-11 21:43:502616def CheckParseErrors(input_api, output_api):
2617 """Check that IDL and JSON files do not contain syntax errors."""
2618 actions = {
2619 '.idl': _GetIDLParseError,
2620 '.json': _GetJSONParseError,
2621 }
2622 # Most JSON files are preprocessed and support comments, but these do not.
2623 json_no_comments_patterns = [
2624 r'^testing[\\/]',
2625 ]
2626 # Only run IDL checker on files in these directories.
2627 idl_included_patterns = [
2628 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2629 r'^extensions[\\/]common[\\/]api[\\/]',
2630 ]
agrievef32bcc72016-04-04 14:57:402631
Sam Maiera6e76d72022-02-11 21:43:502632 def get_action(affected_file):
2633 filename = affected_file.LocalPath()
2634 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402635
Sam Maiera6e76d72022-02-11 21:43:502636 def FilterFile(affected_file):
2637 action = get_action(affected_file)
2638 if not action:
2639 return False
2640 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402641
Sam Maiera6e76d72022-02-11 21:43:502642 if _MatchesFile(input_api,
2643 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2644 return False
2645
2646 if (action == _GetIDLParseError
2647 and not _MatchesFile(input_api, idl_included_patterns, path)):
2648 return False
2649 return True
2650
2651 results = []
2652 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2653 include_deletes=False):
2654 action = get_action(affected_file)
2655 kwargs = {}
2656 if (action == _GetJSONParseError
2657 and _MatchesFile(input_api, json_no_comments_patterns,
2658 affected_file.LocalPath())):
2659 kwargs['eat_comments'] = False
2660 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2661 **kwargs)
2662 if parse_error:
2663 results.append(
2664 output_api.PresubmitError(
2665 '%s could not be parsed: %s' %
2666 (affected_file.LocalPath(), parse_error)))
2667 return results
2668
2669
2670def CheckJavaStyle(input_api, output_api):
2671 """Runs checkstyle on changed java files and returns errors if any exist."""
2672
2673 # Return early if no java files were modified.
2674 if not any(
2675 _IsJavaFile(input_api, f.LocalPath())
2676 for f in input_api.AffectedFiles()):
2677 return []
2678
2679 import sys
2680 original_sys_path = sys.path
2681 try:
2682 sys.path = sys.path + [
2683 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2684 'android', 'checkstyle')
2685 ]
2686 import checkstyle
2687 finally:
2688 # Restore sys.path to what it was before.
2689 sys.path = original_sys_path
2690
2691 return checkstyle.RunCheckstyle(
2692 input_api,
2693 output_api,
2694 'tools/android/checkstyle/chromium-style-5.0.xml',
2695 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2696
2697
2698def CheckPythonDevilInit(input_api, output_api):
2699 """Checks to make sure devil is initialized correctly in python scripts."""
2700 script_common_initialize_pattern = input_api.re.compile(
2701 r'script_common\.InitializeEnvironment\(')
2702 devil_env_config_initialize = input_api.re.compile(
2703 r'devil_env\.config\.Initialize\(')
2704
2705 errors = []
2706
2707 sources = lambda affected_file: input_api.FilterSourceFile(
2708 affected_file,
2709 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2710 r'^build[\\/]android[\\/]devil_chromium\.py',
2711 r'^third_party[\\/].*',
2712 )),
2713 files_to_check=[r'.*\.py$'])
2714
2715 for f in input_api.AffectedSourceFiles(sources):
2716 for line_num, line in f.ChangedContents():
2717 if (script_common_initialize_pattern.search(line)
2718 or devil_env_config_initialize.search(line)):
2719 errors.append("%s:%d" % (f.LocalPath(), line_num))
2720
2721 results = []
2722
2723 if errors:
2724 results.append(
2725 output_api.PresubmitError(
2726 'Devil initialization should always be done using '
2727 'devil_chromium.Initialize() in the chromium project, to use better '
2728 'defaults for dependencies (ex. up-to-date version of adb).',
2729 errors))
2730
2731 return results
2732
2733
2734def _MatchesFile(input_api, patterns, path):
2735 for pattern in patterns:
2736 if input_api.re.search(pattern, path):
2737 return True
2738 return False
2739
2740
2741def _GetOwnersFilesToCheckForIpcOwners(input_api):
2742 """Gets a list of OWNERS files to check for correct security owners.
2743
2744 Returns:
2745 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2746 contain to cover IPC-related files with noparent reviewer rules.
2747 """
2748 # Whether or not a file affects IPC is (mostly) determined by a simple list
2749 # of filename patterns.
2750 file_patterns = [
2751 # Legacy IPC:
2752 '*_messages.cc',
2753 '*_messages*.h',
2754 '*_param_traits*.*',
2755 # Mojo IPC:
2756 '*.mojom',
2757 '*_mojom_traits*.*',
2758 '*_struct_traits*.*',
2759 '*_type_converter*.*',
2760 '*.typemap',
2761 # Android native IPC:
2762 '*.aidl',
2763 # Blink uses a different file naming convention:
2764 '*EnumTraits*.*',
2765 "*MojomTraits*.*",
2766 '*StructTraits*.*',
2767 '*TypeConverter*.*',
2768 ]
2769
2770 # These third_party directories do not contain IPCs, but contain files
2771 # matching the above patterns, which trigger false positives.
2772 exclude_paths = [
2773 'third_party/crashpad/*',
2774 'third_party/blink/renderer/platform/bindings/*',
2775 'third_party/protobuf/benchmarks/python/*',
2776 'third_party/win_build_output/*',
2777 # These files are just used to communicate between class loaders running
2778 # in the same process.
2779 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2780 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2781 ]
2782
2783 # Dictionary mapping an OWNERS file path to Patterns.
2784 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2785 # rules ) to a PatternEntry.
2786 # PatternEntry is a dictionary with two keys:
2787 # - 'files': the files that are matched by this pattern
2788 # - 'rules': the per-file rules needed for this pattern
2789 # For example, if we expect OWNERS file to contain rules for *.mojom and
2790 # *_struct_traits*.*, Patterns might look like this:
2791 # {
2792 # '*.mojom': {
2793 # 'files': ...,
2794 # 'rules': [
2795 # 'per-file *.mojom=set noparent',
2796 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2797 # ],
2798 # },
2799 # '*_struct_traits*.*': {
2800 # 'files': ...,
2801 # 'rules': [
2802 # 'per-file *_struct_traits*.*=set noparent',
2803 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2804 # ],
2805 # },
2806 # }
2807 to_check = {}
2808
2809 def AddPatternToCheck(input_file, pattern):
2810 owners_file = input_api.os_path.join(
2811 input_api.os_path.dirname(input_file.AbsoluteLocalPath()),
2812 'OWNERS')
2813 if owners_file not in to_check:
2814 to_check[owners_file] = {}
2815 if pattern not in to_check[owners_file]:
2816 to_check[owners_file][pattern] = {
2817 'files': [],
2818 'rules': [
2819 'per-file %s=set noparent' % pattern,
2820 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2821 ]
2822 }
2823 to_check[owners_file][pattern]['files'].append(input_file)
2824
2825 # Iterate through the affected files to see what we actually need to check
2826 # for. We should only nag patch authors about per-file rules if a file in that
2827 # directory would match that pattern. If a directory only contains *.mojom
2828 # files and no *_messages*.h files, we should only nag about rules for
2829 # *.mojom files.
2830 for f in input_api.AffectedFiles(include_deletes=False):
2831 # Manifest files don't have a strong naming convention. Instead, try to find
2832 # affected .cc and .h files which look like they contain a manifest
2833 # definition.
2834 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2835 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2836 if (manifest_pattern.search(f.LocalPath())
2837 and not test_manifest_pattern.search(f.LocalPath())):
2838 # We expect all actual service manifest files to contain at least one
2839 # qualified reference to service_manager::Manifest.
2840 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2841 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
2842 for pattern in file_patterns:
2843 if input_api.fnmatch.fnmatch(
2844 input_api.os_path.basename(f.LocalPath()), pattern):
2845 skip = False
2846 for exclude in exclude_paths:
2847 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2848 skip = True
2849 break
2850 if skip:
2851 continue
2852 AddPatternToCheck(f, pattern)
2853 break
2854
2855 return to_check
2856
2857
2858def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2859 """Adds OWNERS files to check for correct Fuchsia security owners."""
2860
2861 file_patterns = [
2862 # Component specifications.
2863 '*.cml', # Component Framework v2.
2864 '*.cmx', # Component Framework v1.
2865
2866 # Fuchsia IDL protocol specifications.
2867 '*.fidl',
2868 ]
2869
2870 # Don't check for owners files for changes in these directories.
2871 exclude_paths = [
2872 'third_party/crashpad/*',
2873 ]
2874
2875 def AddPatternToCheck(input_file, pattern):
2876 owners_file = input_api.os_path.join(
2877 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2878 if owners_file not in to_check:
2879 to_check[owners_file] = {}
2880 if pattern not in to_check[owners_file]:
2881 to_check[owners_file][pattern] = {
2882 'files': [],
2883 'rules': [
2884 'per-file %s=set noparent' % pattern,
2885 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2886 ]
2887 }
2888 to_check[owners_file][pattern]['files'].append(input_file)
2889
2890 # Iterate through the affected files to see what we actually need to check
2891 # for. We should only nag patch authors about per-file rules if a file in that
2892 # directory would match that pattern.
2893 for f in input_api.AffectedFiles(include_deletes=False):
2894 skip = False
2895 for exclude in exclude_paths:
2896 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2897 skip = True
2898 if skip:
2899 continue
2900
2901 for pattern in file_patterns:
2902 if input_api.fnmatch.fnmatch(
2903 input_api.os_path.basename(f.LocalPath()), pattern):
2904 AddPatternToCheck(f, pattern)
2905 break
2906
2907 return to_check
2908
2909
2910def CheckSecurityOwners(input_api, output_api):
2911 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2912 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2913 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
2914
2915 if to_check:
2916 # If there are any OWNERS files to check, there are IPC-related changes in
2917 # this CL. Auto-CC the review list.
2918 output_api.AppendCC('[email protected]')
2919
2920 # Go through the OWNERS files to check, filtering out rules that are already
2921 # present in that OWNERS file.
2922 for owners_file, patterns in to_check.items():
2923 try:
2924 with open(owners_file) as f:
2925 lines = set(f.read().splitlines())
2926 for entry in patterns.values():
2927 entry['rules'] = [
2928 rule for rule in entry['rules'] if rule not in lines
2929 ]
2930 except IOError:
2931 # No OWNERS file, so all the rules are definitely missing.
2932 continue
2933
2934 # All the remaining lines weren't found in OWNERS files, so emit an error.
2935 errors = []
2936 for owners_file, patterns in to_check.items():
2937 missing_lines = []
2938 files = []
2939 for _, entry in patterns.items():
2940 missing_lines.extend(entry['rules'])
2941 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2942 if missing_lines:
2943 errors.append('Because of the presence of files:\n%s\n\n'
2944 '%s needs the following %d lines added:\n\n%s' %
2945 ('\n'.join(files), owners_file, len(missing_lines),
2946 '\n'.join(missing_lines)))
2947
2948 results = []
2949 if errors:
2950 if input_api.is_committing:
2951 output = output_api.PresubmitError
2952 else:
2953 output = output_api.PresubmitPromptWarning
2954 results.append(
2955 output(
2956 'Found OWNERS files that need to be updated for IPC security '
2957 + 'review coverage.\nPlease update the OWNERS files below:',
2958 long_text='\n\n'.join(errors)))
2959
2960 return results
2961
2962
2963def _GetFilesUsingSecurityCriticalFunctions(input_api):
2964 """Checks affected files for changes to security-critical calls. This
2965 function checks the full change diff, to catch both additions/changes
2966 and removals.
2967
2968 Returns a dict keyed by file name, and the value is a set of detected
2969 functions.
2970 """
2971 # Map of function pretty name (displayed in an error) to the pattern to
2972 # match it with.
2973 _PATTERNS_TO_CHECK = {
2974 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
2975 }
2976 _PATTERNS_TO_CHECK = {
2977 k: input_api.re.compile(v)
2978 for k, v in _PATTERNS_TO_CHECK.items()
2979 }
2980
John Budorick47ca3fe2018-02-10 00:53:102981 import os
2982
Sam Maiera6e76d72022-02-11 21:43:502983 # We don't want to trigger on strings within this file.
2984 def presubmit_file_filter(f):
2985 return 'PRESUBMIT.py' != os.path.split(f.LocalPath())[1]
2986
2987 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2988 files_to_functions = {}
2989 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
2990 diff = f.GenerateScmDiff()
2991 for line in diff.split('\n'):
2992 # Not using just RightHandSideLines() because removing a
2993 # call to a security-critical function can be just as important
2994 # as adding or changing the arguments.
2995 if line.startswith('-') or (line.startswith('+')
2996 and not line.startswith('++')):
2997 for name, pattern in _PATTERNS_TO_CHECK.items():
2998 if pattern.search(line):
2999 path = f.LocalPath()
3000 if not path in files_to_functions:
3001 files_to_functions[path] = set()
3002 files_to_functions[path].add(name)
3003 return files_to_functions
3004
3005
3006def CheckSecurityChanges(input_api, output_api):
3007 """Checks that changes involving security-critical functions are reviewed
3008 by the security team.
3009 """
3010 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3011 if not len(files_to_functions):
3012 return []
3013
3014 owner_email, reviewers = (
3015 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3016 input_api, None, approval_needed=input_api.is_committing))
3017
3018 # Load the OWNERS file for security changes.
3019 owners_file = 'ipc/SECURITY_OWNERS'
3020 security_owners = input_api.owners_client.ListOwners(owners_file)
3021 has_security_owner = any([owner in reviewers for owner in security_owners])
3022 if has_security_owner:
3023 return []
3024
3025 msg = 'The following files change calls to security-sensive functions\n' \
3026 'that need to be reviewed by {}.\n'.format(owners_file)
3027 for path, names in files_to_functions.items():
3028 msg += ' {}\n'.format(path)
3029 for name in names:
3030 msg += ' {}\n'.format(name)
3031 msg += '\n'
3032
3033 if input_api.is_committing:
3034 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033035 else:
Sam Maiera6e76d72022-02-11 21:43:503036 output = output_api.PresubmitNotifyResult
3037 return [output(msg)]
3038
3039
3040def CheckSetNoParent(input_api, output_api):
3041 """Checks that set noparent is only used together with an OWNERS file in
3042 //build/OWNERS.setnoparent (see also
3043 //docs/code_reviews.md#owners-files-details)
3044 """
3045 # Return early if no OWNERS files were modified.
3046 if not any(f.LocalPath().endswith('OWNERS')
3047 for f in input_api.AffectedFiles(include_deletes=False)):
3048 return []
3049
3050 errors = []
3051
3052 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3053 allowed_owners_files = set()
3054 with open(allowed_owners_files_file, 'r') as f:
3055 for line in f:
3056 line = line.strip()
3057 if not line or line.startswith('#'):
3058 continue
3059 allowed_owners_files.add(line)
3060
3061 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3062
3063 for f in input_api.AffectedFiles(include_deletes=False):
3064 if not f.LocalPath().endswith('OWNERS'):
3065 continue
3066
3067 found_owners_files = set()
3068 found_set_noparent_lines = dict()
3069
3070 # Parse the OWNERS file.
3071 for lineno, line in enumerate(f.NewContents(), 1):
3072 line = line.strip()
3073 if line.startswith('set noparent'):
3074 found_set_noparent_lines[''] = lineno
3075 if line.startswith('file://'):
3076 if line in allowed_owners_files:
3077 found_owners_files.add('')
3078 if line.startswith('per-file'):
3079 match = per_file_pattern.match(line)
3080 if match:
3081 glob = match.group(1).strip()
3082 directive = match.group(2).strip()
3083 if directive == 'set noparent':
3084 found_set_noparent_lines[glob] = lineno
3085 if directive.startswith('file://'):
3086 if directive in allowed_owners_files:
3087 found_owners_files.add(glob)
3088
3089 # Check that every set noparent line has a corresponding file:// line
3090 # listed in build/OWNERS.setnoparent. An exception is made for top level
3091 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493092 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3093 if (linux_path.count('/') != 1
3094 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503095 for set_noparent_line in found_set_noparent_lines:
3096 if set_noparent_line in found_owners_files:
3097 continue
3098 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493099 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503100 found_set_noparent_lines[set_noparent_line]))
3101
3102 results = []
3103 if errors:
3104 if input_api.is_committing:
3105 output = output_api.PresubmitError
3106 else:
3107 output = output_api.PresubmitPromptWarning
3108 results.append(
3109 output(
3110 'Found the following "set noparent" restrictions in OWNERS files that '
3111 'do not include owners from build/OWNERS.setnoparent:',
3112 long_text='\n\n'.join(errors)))
3113 return results
3114
3115
3116def CheckUselessForwardDeclarations(input_api, output_api):
3117 """Checks that added or removed lines in non third party affected
3118 header files do not lead to new useless class or struct forward
3119 declaration.
3120 """
3121 results = []
3122 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3123 input_api.re.MULTILINE)
3124 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3125 input_api.re.MULTILINE)
3126 for f in input_api.AffectedFiles(include_deletes=False):
3127 if (f.LocalPath().startswith('third_party')
3128 and not f.LocalPath().startswith('third_party/blink')
3129 and not f.LocalPath().startswith('third_party\\blink')):
3130 continue
3131
3132 if not f.LocalPath().endswith('.h'):
3133 continue
3134
3135 contents = input_api.ReadFile(f)
3136 fwd_decls = input_api.re.findall(class_pattern, contents)
3137 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3138
3139 useless_fwd_decls = []
3140 for decl in fwd_decls:
3141 count = sum(1 for _ in input_api.re.finditer(
3142 r'\b%s\b' % input_api.re.escape(decl), contents))
3143 if count == 1:
3144 useless_fwd_decls.append(decl)
3145
3146 if not useless_fwd_decls:
3147 continue
3148
3149 for line in f.GenerateScmDiff().splitlines():
3150 if (line.startswith('-') and not line.startswith('--')
3151 or line.startswith('+') and not line.startswith('++')):
3152 for decl in useless_fwd_decls:
3153 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3154 results.append(
3155 output_api.PresubmitPromptWarning(
3156 '%s: %s forward declaration is no longer needed'
3157 % (f.LocalPath(), decl)))
3158 useless_fwd_decls.remove(decl)
3159
3160 return results
3161
3162
3163def _CheckAndroidDebuggableBuild(input_api, output_api):
3164 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3165 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3166 this is a debuggable build of Android.
3167 """
3168 build_type_check_pattern = input_api.re.compile(
3169 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3170
3171 errors = []
3172
3173 sources = lambda affected_file: input_api.FilterSourceFile(
3174 affected_file,
3175 files_to_skip=(
3176 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3177 DEFAULT_FILES_TO_SKIP + (
3178 r"^android_webview[\\/]support_library[\\/]"
3179 "boundary_interfaces[\\/]",
3180 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3181 r'^third_party[\\/].*',
3182 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3183 r"webview[\\/]chromium[\\/]License.*",
3184 )),
3185 files_to_check=[r'.*\.java$'])
3186
3187 for f in input_api.AffectedSourceFiles(sources):
3188 for line_num, line in f.ChangedContents():
3189 if build_type_check_pattern.search(line):
3190 errors.append("%s:%d" % (f.LocalPath(), line_num))
3191
3192 results = []
3193
3194 if errors:
3195 results.append(
3196 output_api.PresubmitPromptWarning(
3197 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3198 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3199
3200 return results
3201
3202# TODO: add unit tests
3203def _CheckAndroidToastUsage(input_api, output_api):
3204 """Checks that code uses org.chromium.ui.widget.Toast instead of
3205 android.widget.Toast (Chromium Toast doesn't force hardware
3206 acceleration on low-end devices, saving memory).
3207 """
3208 toast_import_pattern = input_api.re.compile(
3209 r'^import android\.widget\.Toast;$')
3210
3211 errors = []
3212
3213 sources = lambda affected_file: input_api.FilterSourceFile(
3214 affected_file,
3215 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3216 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3217 r'^remoting[\\/].*')),
3218 files_to_check=[r'.*\.java$'])
3219
3220 for f in input_api.AffectedSourceFiles(sources):
3221 for line_num, line in f.ChangedContents():
3222 if toast_import_pattern.search(line):
3223 errors.append("%s:%d" % (f.LocalPath(), line_num))
3224
3225 results = []
3226
3227 if errors:
3228 results.append(
3229 output_api.PresubmitError(
3230 'android.widget.Toast usage is detected. Android toasts use hardware'
3231 ' acceleration, and can be\ncostly on low-end devices. Please use'
3232 ' org.chromium.ui.widget.Toast instead.\n'
3233 'Contact [email protected] if you have any questions.',
3234 errors))
3235
3236 return results
3237
3238
3239def _CheckAndroidCrLogUsage(input_api, output_api):
3240 """Checks that new logs using org.chromium.base.Log:
3241 - Are using 'TAG' as variable name for the tags (warn)
3242 - Are using a tag that is shorter than 20 characters (error)
3243 """
3244
3245 # Do not check format of logs in the given files
3246 cr_log_check_excluded_paths = [
3247 # //chrome/android/webapk cannot depend on //base
3248 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3249 # WebView license viewer code cannot depend on //base; used in stub APK.
3250 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3251 r"webview[\\/]chromium[\\/]License.*",
3252 # The customtabs_benchmark is a small app that does not depend on Chromium
3253 # java pieces.
3254 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3255 ]
3256
3257 cr_log_import_pattern = input_api.re.compile(
3258 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3259 class_in_base_pattern = input_api.re.compile(
3260 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3261 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3262 input_api.re.MULTILINE)
3263 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3264 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3265 log_decl_pattern = input_api.re.compile(
3266 r'static final String TAG = "(?P<name>(.*))"')
3267 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3268
3269 REF_MSG = ('See docs/android_logging.md for more info.')
3270 sources = lambda x: input_api.FilterSourceFile(
3271 x,
3272 files_to_check=[r'.*\.java$'],
3273 files_to_skip=cr_log_check_excluded_paths)
3274
3275 tag_decl_errors = []
3276 tag_length_errors = []
3277 tag_errors = []
3278 tag_with_dot_errors = []
3279 util_log_errors = []
3280
3281 for f in input_api.AffectedSourceFiles(sources):
3282 file_content = input_api.ReadFile(f)
3283 has_modified_logs = False
3284 # Per line checks
3285 if (cr_log_import_pattern.search(file_content)
3286 or (class_in_base_pattern.search(file_content)
3287 and not has_some_log_import_pattern.search(file_content))):
3288 # Checks to run for files using cr log
3289 for line_num, line in f.ChangedContents():
3290 if rough_log_decl_pattern.search(line):
3291 has_modified_logs = True
3292
3293 # Check if the new line is doing some logging
3294 match = log_call_pattern.search(line)
3295 if match:
3296 has_modified_logs = True
3297
3298 # Make sure it uses "TAG"
3299 if not match.group('tag') == 'TAG':
3300 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3301 else:
3302 # Report non cr Log function calls in changed lines
3303 for line_num, line in f.ChangedContents():
3304 if log_call_pattern.search(line):
3305 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3306
3307 # Per file checks
3308 if has_modified_logs:
3309 # Make sure the tag is using the "cr" prefix and is not too long
3310 match = log_decl_pattern.search(file_content)
3311 tag_name = match.group('name') if match else None
3312 if not tag_name:
3313 tag_decl_errors.append(f.LocalPath())
3314 elif len(tag_name) > 20:
3315 tag_length_errors.append(f.LocalPath())
3316 elif '.' in tag_name:
3317 tag_with_dot_errors.append(f.LocalPath())
3318
3319 results = []
3320 if tag_decl_errors:
3321 results.append(
3322 output_api.PresubmitPromptWarning(
3323 'Please define your tags using the suggested format: .\n'
3324 '"private static final String TAG = "<package tag>".\n'
3325 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3326 tag_decl_errors))
3327
3328 if tag_length_errors:
3329 results.append(
3330 output_api.PresubmitError(
3331 'The tag length is restricted by the system to be at most '
3332 '20 characters.\n' + REF_MSG, tag_length_errors))
3333
3334 if tag_errors:
3335 results.append(
3336 output_api.PresubmitPromptWarning(
3337 'Please use a variable named "TAG" for your log tags.\n' +
3338 REF_MSG, tag_errors))
3339
3340 if util_log_errors:
3341 results.append(
3342 output_api.PresubmitPromptWarning(
3343 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3344 util_log_errors))
3345
3346 if tag_with_dot_errors:
3347 results.append(
3348 output_api.PresubmitPromptWarning(
3349 'Dot in log tags cause them to be elided in crash reports.\n' +
3350 REF_MSG, tag_with_dot_errors))
3351
3352 return results
3353
3354
3355def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3356 """Checks that junit.framework.* is no longer used."""
3357 deprecated_junit_framework_pattern = input_api.re.compile(
3358 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3359 sources = lambda x: input_api.FilterSourceFile(
3360 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3361 errors = []
3362 for f in input_api.AffectedFiles(file_filter=sources):
3363 for line_num, line in f.ChangedContents():
3364 if deprecated_junit_framework_pattern.search(line):
3365 errors.append("%s:%d" % (f.LocalPath(), line_num))
3366
3367 results = []
3368 if errors:
3369 results.append(
3370 output_api.PresubmitError(
3371 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3372 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3373 ' if you have any question.', errors))
3374 return results
3375
3376
3377def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3378 """Checks that if new Java test classes have inheritance.
3379 Either the new test class is JUnit3 test or it is a JUnit4 test class
3380 with a base class, either case is undesirable.
3381 """
3382 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3383
3384 sources = lambda x: input_api.FilterSourceFile(
3385 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3386 errors = []
3387 for f in input_api.AffectedFiles(file_filter=sources):
3388 if not f.OldContents():
3389 class_declaration_start_flag = False
3390 for line_num, line in f.ChangedContents():
3391 if class_declaration_pattern.search(line):
3392 class_declaration_start_flag = True
3393 if class_declaration_start_flag and ' extends ' in line:
3394 errors.append('%s:%d' % (f.LocalPath(), line_num))
3395 if '{' in line:
3396 class_declaration_start_flag = False
3397
3398 results = []
3399 if errors:
3400 results.append(
3401 output_api.PresubmitPromptWarning(
3402 'The newly created files include Test classes that inherits from base'
3403 ' class. Please do not use inheritance in JUnit4 tests or add new'
3404 ' JUnit3 tests. Contact [email protected] if you have any'
3405 ' questions.', errors))
3406 return results
3407
3408
3409def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3410 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3411 deprecated_annotation_import_pattern = input_api.re.compile(
3412 r'^import android\.test\.suitebuilder\.annotation\..*;',
3413 input_api.re.MULTILINE)
3414 sources = lambda x: input_api.FilterSourceFile(
3415 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3416 errors = []
3417 for f in input_api.AffectedFiles(file_filter=sources):
3418 for line_num, line in f.ChangedContents():
3419 if deprecated_annotation_import_pattern.search(line):
3420 errors.append("%s:%d" % (f.LocalPath(), line_num))
3421
3422 results = []
3423 if errors:
3424 results.append(
3425 output_api.PresubmitError(
3426 'Annotations in android.test.suitebuilder.annotation have been'
3427 ' deprecated since API level 24. Please use android.support.test.filters'
3428 ' from //third_party/android_support_test_runner:runner_java instead.'
3429 ' Contact [email protected] if you have any questions.',
3430 errors))
3431 return results
3432
3433
3434def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3435 """Checks if MDPI assets are placed in a correct directory."""
3436 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3437 ('/res/drawable/' in f.LocalPath() or
3438 '/res/drawable-ldrtl/' in f.LocalPath()))
3439 errors = []
3440 for f in input_api.AffectedFiles(include_deletes=False,
3441 file_filter=file_filter):
3442 errors.append(' %s' % f.LocalPath())
3443
3444 results = []
3445 if errors:
3446 results.append(
3447 output_api.PresubmitError(
3448 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3449 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3450 '/res/drawable-ldrtl/.\n'
3451 'Contact [email protected] if you have questions.', errors))
3452 return results
3453
3454
3455def _CheckAndroidWebkitImports(input_api, output_api):
3456 """Checks that code uses org.chromium.base.Callback instead of
3457 android.webview.ValueCallback except in the WebView glue layer
3458 and WebLayer.
3459 """
3460 valuecallback_import_pattern = input_api.re.compile(
3461 r'^import android\.webkit\.ValueCallback;$')
3462
3463 errors = []
3464
3465 sources = lambda affected_file: input_api.FilterSourceFile(
3466 affected_file,
3467 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3468 DEFAULT_FILES_TO_SKIP + (
3469 r'^android_webview[\\/]glue[\\/].*',
3470 r'^weblayer[\\/].*',
3471 )),
3472 files_to_check=[r'.*\.java$'])
3473
3474 for f in input_api.AffectedSourceFiles(sources):
3475 for line_num, line in f.ChangedContents():
3476 if valuecallback_import_pattern.search(line):
3477 errors.append("%s:%d" % (f.LocalPath(), line_num))
3478
3479 results = []
3480
3481 if errors:
3482 results.append(
3483 output_api.PresubmitError(
3484 'android.webkit.ValueCallback usage is detected outside of the glue'
3485 ' layer. To stay compatible with the support library, android.webkit.*'
3486 ' classes should only be used inside the glue layer and'
3487 ' org.chromium.base.Callback should be used instead.', errors))
3488
3489 return results
3490
3491
3492def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3493 """Checks Android XML styles """
3494
3495 # Return early if no relevant files were modified.
3496 if not any(
3497 _IsXmlOrGrdFile(input_api, f.LocalPath())
3498 for f in input_api.AffectedFiles(include_deletes=False)):
3499 return []
3500
3501 import sys
3502 original_sys_path = sys.path
3503 try:
3504 sys.path = sys.path + [
3505 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3506 'android', 'checkxmlstyle')
3507 ]
3508 import checkxmlstyle
3509 finally:
3510 # Restore sys.path to what it was before.
3511 sys.path = original_sys_path
3512
3513 if is_check_on_upload:
3514 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3515 else:
3516 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3517
3518
3519def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3520 """Checks Android Infobar Deprecation """
3521
3522 import sys
3523 original_sys_path = sys.path
3524 try:
3525 sys.path = sys.path + [
3526 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3527 'android', 'infobar_deprecation')
3528 ]
3529 import infobar_deprecation
3530 finally:
3531 # Restore sys.path to what it was before.
3532 sys.path = original_sys_path
3533
3534 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3535
3536
3537class _PydepsCheckerResult:
3538 def __init__(self, cmd, pydeps_path, process, old_contents):
3539 self._cmd = cmd
3540 self._pydeps_path = pydeps_path
3541 self._process = process
3542 self._old_contents = old_contents
3543
3544 def GetError(self):
3545 """Returns an error message, or None."""
3546 import difflib
3547 if self._process.wait() != 0:
3548 # STDERR should already be printed.
3549 return 'Command failed: ' + self._cmd
3550 new_contents = self._process.stdout.read().splitlines()[2:]
3551 if self._old_contents != new_contents:
3552 diff = '\n'.join(
3553 difflib.context_diff(self._old_contents, new_contents))
3554 return ('File is stale: {}\n'
3555 'Diff (apply to fix):\n'
3556 '{}\n'
3557 'To regenerate, run:\n\n'
3558 ' {}').format(self._pydeps_path, diff, self._cmd)
3559 return None
3560
3561
3562class PydepsChecker:
3563 def __init__(self, input_api, pydeps_files):
3564 self._file_cache = {}
3565 self._input_api = input_api
3566 self._pydeps_files = pydeps_files
3567
3568 def _LoadFile(self, path):
3569 """Returns the list of paths within a .pydeps file relative to //."""
3570 if path not in self._file_cache:
3571 with open(path, encoding='utf-8') as f:
3572 self._file_cache[path] = f.read()
3573 return self._file_cache[path]
3574
3575 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3576 """Returns an interable of paths within the .pydep, relativized to //."""
3577 pydeps_data = self._LoadFile(pydeps_path)
3578 uses_gn_paths = '--gn-paths' in pydeps_data
3579 entries = (l for l in pydeps_data.splitlines()
3580 if not l.startswith('#'))
3581 if uses_gn_paths:
3582 # Paths look like: //foo/bar/baz
3583 return (e[2:] for e in entries)
3584 else:
3585 # Paths look like: path/relative/to/file.pydeps
3586 os_path = self._input_api.os_path
3587 pydeps_dir = os_path.dirname(pydeps_path)
3588 return (os_path.normpath(os_path.join(pydeps_dir, e))
3589 for e in entries)
3590
3591 def _CreateFilesToPydepsMap(self):
3592 """Returns a map of local_path -> list_of_pydeps."""
3593 ret = {}
3594 for pydep_local_path in self._pydeps_files:
3595 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3596 ret.setdefault(path, []).append(pydep_local_path)
3597 return ret
3598
3599 def ComputeAffectedPydeps(self):
3600 """Returns an iterable of .pydeps files that might need regenerating."""
3601 affected_pydeps = set()
3602 file_to_pydeps_map = None
3603 for f in self._input_api.AffectedFiles(include_deletes=True):
3604 local_path = f.LocalPath()
3605 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3606 # subrepositories. We can't figure out which files change, so re-check
3607 # all files.
3608 # Changes to print_python_deps.py affect all .pydeps.
3609 if local_path in ('DEPS', 'PRESUBMIT.py'
3610 ) or local_path.endswith('print_python_deps.py'):
3611 return self._pydeps_files
3612 elif local_path.endswith('.pydeps'):
3613 if local_path in self._pydeps_files:
3614 affected_pydeps.add(local_path)
3615 elif local_path.endswith('.py'):
3616 if file_to_pydeps_map is None:
3617 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3618 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3619 return affected_pydeps
3620
3621 def DetermineIfStaleAsync(self, pydeps_path):
3622 """Runs print_python_deps.py to see if the files is stale."""
3623 import os
3624
3625 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3626 if old_pydeps_data:
3627 cmd = old_pydeps_data[1][1:].strip()
3628 if '--output' not in cmd:
3629 cmd += ' --output ' + pydeps_path
3630 old_contents = old_pydeps_data[2:]
3631 else:
3632 # A default cmd that should work in most cases (as long as pydeps filename
3633 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3634 # file is empty/new.
3635 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3636 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3637 old_contents = []
3638 env = dict(os.environ)
3639 env['PYTHONDONTWRITEBYTECODE'] = '1'
3640 process = self._input_api.subprocess.Popen(
3641 cmd + ' --output ""',
3642 shell=True,
3643 env=env,
3644 stdout=self._input_api.subprocess.PIPE,
3645 encoding='utf-8')
3646 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403647
3648
Tibor Goldschwendt360793f72019-06-25 18:23:493649def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503650 args = {}
3651 with open('build/config/gclient_args.gni', 'r') as f:
3652 for line in f:
3653 line = line.strip()
3654 if not line or line.startswith('#'):
3655 continue
3656 attribute, value = line.split('=')
3657 args[attribute.strip()] = value.strip()
3658 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493659
3660
Saagar Sanghavifceeaae2020-08-12 16:40:363661def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503662 """Checks if a .pydeps file needs to be regenerated."""
3663 # This check is for Python dependency lists (.pydeps files), and involves
3664 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3665 # doesn't work on Windows and Mac, so skip it on other platforms.
3666 if not input_api.platform.startswith('linux'):
3667 return []
Erik Staabc734cd7a2021-11-23 03:11:523668
Sam Maiera6e76d72022-02-11 21:43:503669 results = []
3670 # First, check for new / deleted .pydeps.
3671 for f in input_api.AffectedFiles(include_deletes=True):
3672 # Check whether we are running the presubmit check for a file in src.
3673 # f.LocalPath is relative to repo (src, or internal repo).
3674 # os_path.exists is relative to src repo.
3675 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3676 # to src and we can conclude that the pydeps is in src.
3677 if f.LocalPath().endswith('.pydeps'):
3678 if input_api.os_path.exists(f.LocalPath()):
3679 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3680 results.append(
3681 output_api.PresubmitError(
3682 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3683 'remove %s' % f.LocalPath()))
3684 elif f.Action() != 'D' and f.LocalPath(
3685 ) not in _ALL_PYDEPS_FILES:
3686 results.append(
3687 output_api.PresubmitError(
3688 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3689 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403690
Sam Maiera6e76d72022-02-11 21:43:503691 if results:
3692 return results
3693
3694 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3695 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3696 affected_pydeps = set(checker.ComputeAffectedPydeps())
3697 affected_android_pydeps = affected_pydeps.intersection(
3698 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3699 if affected_android_pydeps and not is_android:
3700 results.append(
3701 output_api.PresubmitPromptOrNotify(
3702 'You have changed python files that may affect pydeps for android\n'
3703 'specific scripts. However, the relevant presumbit check cannot be\n'
3704 'run because you are not using an Android checkout. To validate that\n'
3705 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3706 'use the android-internal-presubmit optional trybot.\n'
3707 'Possibly stale pydeps files:\n{}'.format(
3708 '\n'.join(affected_android_pydeps))))
3709
3710 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3711 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3712 # Process these concurrently, as each one takes 1-2 seconds.
3713 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3714 for result in pydep_results:
3715 error_msg = result.GetError()
3716 if error_msg:
3717 results.append(output_api.PresubmitError(error_msg))
3718
agrievef32bcc72016-04-04 14:57:403719 return results
3720
agrievef32bcc72016-04-04 14:57:403721
Saagar Sanghavifceeaae2020-08-12 16:40:363722def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503723 """Checks to make sure no header files have |Singleton<|."""
3724
3725 def FileFilter(affected_file):
3726 # It's ok for base/memory/singleton.h to have |Singleton<|.
3727 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3728 (r"^base[\\/]memory[\\/]singleton\.h$",
3729 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443730 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503731 return input_api.FilterSourceFile(affected_file,
3732 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433733
Sam Maiera6e76d72022-02-11 21:43:503734 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3735 files = []
3736 for f in input_api.AffectedSourceFiles(FileFilter):
3737 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3738 or f.LocalPath().endswith('.hpp')
3739 or f.LocalPath().endswith('.inl')):
3740 contents = input_api.ReadFile(f)
3741 for line in contents.splitlines(False):
3742 if (not line.lstrip().startswith('//')
3743 and # Strip C++ comment.
3744 pattern.search(line)):
3745 files.append(f)
3746 break
glidere61efad2015-02-18 17:39:433747
Sam Maiera6e76d72022-02-11 21:43:503748 if files:
3749 return [
3750 output_api.PresubmitError(
3751 'Found base::Singleton<T> in the following header files.\n' +
3752 'Please move them to an appropriate source file so that the ' +
3753 'template gets instantiated in a single compilation unit.',
3754 files)
3755 ]
3756 return []
glidere61efad2015-02-18 17:39:433757
3758
[email protected]fd20b902014-05-09 02:14:533759_DEPRECATED_CSS = [
3760 # Values
3761 ( "-webkit-box", "flex" ),
3762 ( "-webkit-inline-box", "inline-flex" ),
3763 ( "-webkit-flex", "flex" ),
3764 ( "-webkit-inline-flex", "inline-flex" ),
3765 ( "-webkit-min-content", "min-content" ),
3766 ( "-webkit-max-content", "max-content" ),
3767
3768 # Properties
3769 ( "-webkit-background-clip", "background-clip" ),
3770 ( "-webkit-background-origin", "background-origin" ),
3771 ( "-webkit-background-size", "background-size" ),
3772 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443773 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533774
3775 # Functions
3776 ( "-webkit-gradient", "gradient" ),
3777 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3778 ( "-webkit-linear-gradient", "linear-gradient" ),
3779 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3780 ( "-webkit-radial-gradient", "radial-gradient" ),
3781 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3782]
3783
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203784
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493785# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363786def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503787 """ Make sure that we don't use deprecated CSS
3788 properties, functions or values. Our external
3789 documentation and iOS CSS for dom distiller
3790 (reader mode) are ignored by the hooks as it
3791 needs to be consumed by WebKit. """
3792 results = []
3793 file_inclusion_pattern = [r".+\.css$"]
3794 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3795 input_api.DEFAULT_FILES_TO_SKIP +
3796 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3797 r"^native_client_sdk"))
3798 file_filter = lambda f: input_api.FilterSourceFile(
3799 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3800 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3801 for line_num, line in fpath.ChangedContents():
3802 for (deprecated_value, value) in _DEPRECATED_CSS:
3803 if deprecated_value in line:
3804 results.append(
3805 output_api.PresubmitError(
3806 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3807 (fpath.LocalPath(), line_num, deprecated_value,
3808 value)))
3809 return results
[email protected]fd20b902014-05-09 02:14:533810
mohan.reddyf21db962014-10-16 12:26:473811
Saagar Sanghavifceeaae2020-08-12 16:40:363812def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503813 bad_files = {}
3814 for f in input_api.AffectedFiles(include_deletes=False):
3815 if (f.LocalPath().startswith('third_party')
3816 and not f.LocalPath().startswith('third_party/blink')
3817 and not f.LocalPath().startswith('third_party\\blink')):
3818 continue
rlanday6802cf632017-05-30 17:48:363819
Sam Maiera6e76d72022-02-11 21:43:503820 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3821 continue
rlanday6802cf632017-05-30 17:48:363822
Sam Maiera6e76d72022-02-11 21:43:503823 relative_includes = [
3824 line for _, line in f.ChangedContents()
3825 if "#include" in line and "../" in line
3826 ]
3827 if not relative_includes:
3828 continue
3829 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363830
Sam Maiera6e76d72022-02-11 21:43:503831 if not bad_files:
3832 return []
rlanday6802cf632017-05-30 17:48:363833
Sam Maiera6e76d72022-02-11 21:43:503834 error_descriptions = []
3835 for file_path, bad_lines in bad_files.items():
3836 error_description = file_path
3837 for line in bad_lines:
3838 error_description += '\n ' + line
3839 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363840
Sam Maiera6e76d72022-02-11 21:43:503841 results = []
3842 results.append(
3843 output_api.PresubmitError(
3844 'You added one or more relative #include paths (including "../").\n'
3845 'These shouldn\'t be used because they can be used to include headers\n'
3846 'from code that\'s not correctly specified as a dependency in the\n'
3847 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363848
Sam Maiera6e76d72022-02-11 21:43:503849 return results
rlanday6802cf632017-05-30 17:48:363850
Takeshi Yoshinoe387aa32017-08-02 13:16:133851
Saagar Sanghavifceeaae2020-08-12 16:40:363852def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503853 """Check that nobody tries to include a cc file. It's a relatively
3854 common error which results in duplicate symbols in object
3855 files. This may not always break the build until someone later gets
3856 very confusing linking errors."""
3857 results = []
3858 for f in input_api.AffectedFiles(include_deletes=False):
3859 # We let third_party code do whatever it wants
3860 if (f.LocalPath().startswith('third_party')
3861 and not f.LocalPath().startswith('third_party/blink')
3862 and not f.LocalPath().startswith('third_party\\blink')):
3863 continue
Daniel Bratell65b033262019-04-23 08:17:063864
Sam Maiera6e76d72022-02-11 21:43:503865 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3866 continue
Daniel Bratell65b033262019-04-23 08:17:063867
Sam Maiera6e76d72022-02-11 21:43:503868 for _, line in f.ChangedContents():
3869 if line.startswith('#include "'):
3870 included_file = line.split('"')[1]
3871 if _IsCPlusPlusFile(input_api, included_file):
3872 # The most common naming for external files with C++ code,
3873 # apart from standard headers, is to call them foo.inc, but
3874 # Chromium sometimes uses foo-inc.cc so allow that as well.
3875 if not included_file.endswith(('.h', '-inc.cc')):
3876 results.append(
3877 output_api.PresubmitError(
3878 'Only header files or .inc files should be included in other\n'
3879 'C++ files. Compiling the contents of a cc file more than once\n'
3880 'will cause duplicate information in the build which may later\n'
3881 'result in strange link_errors.\n' +
3882 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063883
Sam Maiera6e76d72022-02-11 21:43:503884 return results
Daniel Bratell65b033262019-04-23 08:17:063885
3886
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203887def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503888 if not isinstance(key, ast.Str):
3889 return 'Key at line %d must be a string literal' % key.lineno
3890 if not isinstance(value, ast.Dict):
3891 return 'Value at line %d must be a dict' % value.lineno
3892 if len(value.keys) != 1:
3893 return 'Dict at line %d must have single entry' % value.lineno
3894 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3895 return (
3896 'Entry at line %d must have a string literal \'filepath\' as key' %
3897 value.lineno)
3898 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133899
Takeshi Yoshinoe387aa32017-08-02 13:16:133900
Sergey Ulanov4af16052018-11-08 02:41:463901def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503902 if not isinstance(key, ast.Str):
3903 return 'Key at line %d must be a string literal' % key.lineno
3904 if not isinstance(value, ast.List):
3905 return 'Value at line %d must be a list' % value.lineno
3906 for element in value.elts:
3907 if not isinstance(element, ast.Str):
3908 return 'Watchlist elements on line %d is not a string' % key.lineno
3909 if not email_regex.match(element.s):
3910 return ('Watchlist element on line %d doesn\'t look like a valid '
3911 + 'email: %s') % (key.lineno, element.s)
3912 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133913
Takeshi Yoshinoe387aa32017-08-02 13:16:133914
Sergey Ulanov4af16052018-11-08 02:41:463915def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:503916 mismatch_template = (
3917 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3918 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133919
Sam Maiera6e76d72022-02-11 21:43:503920 email_regex = input_api.re.compile(
3921 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:463922
Sam Maiera6e76d72022-02-11 21:43:503923 ast = input_api.ast
3924 i = 0
3925 last_key = ''
3926 while True:
3927 if i >= len(wd_dict.keys):
3928 if i >= len(w_dict.keys):
3929 return None
3930 return mismatch_template % ('missing',
3931 'line %d' % w_dict.keys[i].lineno)
3932 elif i >= len(w_dict.keys):
3933 return (mismatch_template %
3934 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133935
Sam Maiera6e76d72022-02-11 21:43:503936 wd_key = wd_dict.keys[i]
3937 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133938
Sam Maiera6e76d72022-02-11 21:43:503939 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
3940 wd_dict.values[i], ast)
3941 if result is not None:
3942 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133943
Sam Maiera6e76d72022-02-11 21:43:503944 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
3945 email_regex)
3946 if result is not None:
3947 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203948
Sam Maiera6e76d72022-02-11 21:43:503949 if wd_key.s != w_key.s:
3950 return mismatch_template % ('%s at line %d' %
3951 (wd_key.s, wd_key.lineno),
3952 '%s at line %d' %
3953 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203954
Sam Maiera6e76d72022-02-11 21:43:503955 if wd_key.s < last_key:
3956 return (
3957 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
3958 % (wd_key.lineno, w_key.lineno))
3959 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203960
Sam Maiera6e76d72022-02-11 21:43:503961 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962
3963
Sergey Ulanov4af16052018-11-08 02:41:463964def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:503965 ast = input_api.ast
3966 if not isinstance(expression, ast.Expression):
3967 return 'WATCHLISTS file must contain a valid expression'
3968 dictionary = expression.body
3969 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3970 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203971
Sam Maiera6e76d72022-02-11 21:43:503972 first_key = dictionary.keys[0]
3973 first_value = dictionary.values[0]
3974 second_key = dictionary.keys[1]
3975 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976
Sam Maiera6e76d72022-02-11 21:43:503977 if (not isinstance(first_key, ast.Str)
3978 or first_key.s != 'WATCHLIST_DEFINITIONS'
3979 or not isinstance(first_value, ast.Dict)):
3980 return ('The first entry of the dict in WATCHLISTS file must be '
3981 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203982
Sam Maiera6e76d72022-02-11 21:43:503983 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
3984 or not isinstance(second_value, ast.Dict)):
3985 return ('The second entry of the dict in WATCHLISTS file must be '
3986 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203987
Sam Maiera6e76d72022-02-11 21:43:503988 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133989
3990
Saagar Sanghavifceeaae2020-08-12 16:40:363991def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503992 for f in input_api.AffectedFiles(include_deletes=False):
3993 if f.LocalPath() == 'WATCHLISTS':
3994 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:133995
Sam Maiera6e76d72022-02-11 21:43:503996 try:
3997 # First, make sure that it can be evaluated.
3998 input_api.ast.literal_eval(contents)
3999 # Get an AST tree for it and scan the tree for detailed style checking.
4000 expression = input_api.ast.parse(contents,
4001 filename='WATCHLISTS',
4002 mode='eval')
4003 except ValueError as e:
4004 return [
4005 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4006 long_text=repr(e))
4007 ]
4008 except SyntaxError as e:
4009 return [
4010 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4011 long_text=repr(e))
4012 ]
4013 except TypeError as e:
4014 return [
4015 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4016 long_text=repr(e))
4017 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134018
Sam Maiera6e76d72022-02-11 21:43:504019 result = _CheckWATCHLISTSSyntax(expression, input_api)
4020 if result is not None:
4021 return [output_api.PresubmitError(result)]
4022 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134023
Sam Maiera6e76d72022-02-11 21:43:504024 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134025
4026
Andrew Grieve1b290e4a22020-11-24 20:07:014027def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504028 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014029
Sam Maiera6e76d72022-02-11 21:43:504030 As documented at //build/docs/writing_gn_templates.md
4031 """
Andrew Grieve1b290e4a22020-11-24 20:07:014032
Sam Maiera6e76d72022-02-11 21:43:504033 def gn_files(f):
4034 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014035
Sam Maiera6e76d72022-02-11 21:43:504036 problems = []
4037 for f in input_api.AffectedSourceFiles(gn_files):
4038 for line_num, line in f.ChangedContents():
4039 if 'forward_variables_from(invoker, "*")' in line:
4040 problems.append(
4041 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4042 (f.LocalPath(), line_num))
4043
4044 if problems:
4045 return [
4046 output_api.PresubmitPromptWarning(
4047 'forward_variables_from("*") without exclusions',
4048 items=sorted(problems),
4049 long_text=(
4050 'The variables "visibilty" and "test_only" should be '
4051 'explicitly listed in forward_variables_from(). For more '
4052 'details, see:\n'
4053 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4054 'build/docs/writing_gn_templates.md'
4055 '#Using-forward_variables_from'))
4056 ]
4057 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014058
4059
Saagar Sanghavifceeaae2020-08-12 16:40:364060def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504061 """Checks that newly added header files have corresponding GN changes.
4062 Note that this is only a heuristic. To be precise, run script:
4063 build/check_gn_headers.py.
4064 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194065
Sam Maiera6e76d72022-02-11 21:43:504066 def headers(f):
4067 return input_api.FilterSourceFile(
4068 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194069
Sam Maiera6e76d72022-02-11 21:43:504070 new_headers = []
4071 for f in input_api.AffectedSourceFiles(headers):
4072 if f.Action() != 'A':
4073 continue
4074 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194075
Sam Maiera6e76d72022-02-11 21:43:504076 def gn_files(f):
4077 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194078
Sam Maiera6e76d72022-02-11 21:43:504079 all_gn_changed_contents = ''
4080 for f in input_api.AffectedSourceFiles(gn_files):
4081 for _, line in f.ChangedContents():
4082 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194083
Sam Maiera6e76d72022-02-11 21:43:504084 problems = []
4085 for header in new_headers:
4086 basename = input_api.os_path.basename(header)
4087 if basename not in all_gn_changed_contents:
4088 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194089
Sam Maiera6e76d72022-02-11 21:43:504090 if problems:
4091 return [
4092 output_api.PresubmitPromptWarning(
4093 'Missing GN changes for new header files',
4094 items=sorted(problems),
4095 long_text=
4096 'Please double check whether newly added header files need '
4097 'corresponding changes in gn or gni files.\nThis checking is only a '
4098 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4099 'Read https://crbug.com/661774 for more info.')
4100 ]
4101 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194102
4103
Saagar Sanghavifceeaae2020-08-12 16:40:364104def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504105 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024106
Sam Maiera6e76d72022-02-11 21:43:504107 This assumes we won't intentionally reference one product from the other
4108 product.
4109 """
4110 all_problems = []
4111 test_cases = [{
4112 "filename_postfix": "google_chrome_strings.grd",
4113 "correct_name": "Chrome",
4114 "incorrect_name": "Chromium",
4115 }, {
4116 "filename_postfix": "chromium_strings.grd",
4117 "correct_name": "Chromium",
4118 "incorrect_name": "Chrome",
4119 }]
Michael Giuffridad3bc8672018-10-25 22:48:024120
Sam Maiera6e76d72022-02-11 21:43:504121 for test_case in test_cases:
4122 problems = []
4123 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4124 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024125
Sam Maiera6e76d72022-02-11 21:43:504126 # Check each new line. Can yield false positives in multiline comments, but
4127 # easier than trying to parse the XML because messages can have nested
4128 # children, and associating message elements with affected lines is hard.
4129 for f in input_api.AffectedSourceFiles(filename_filter):
4130 for line_num, line in f.ChangedContents():
4131 if "<message" in line or "<!--" in line or "-->" in line:
4132 continue
4133 if test_case["incorrect_name"] in line:
4134 problems.append("Incorrect product name in %s:%d" %
4135 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024136
Sam Maiera6e76d72022-02-11 21:43:504137 if problems:
4138 message = (
4139 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4140 % (test_case["correct_name"], test_case["correct_name"],
4141 test_case["incorrect_name"]))
4142 all_problems.append(
4143 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024144
Sam Maiera6e76d72022-02-11 21:43:504145 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024146
4147
Saagar Sanghavifceeaae2020-08-12 16:40:364148def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504149 """Avoid large files, especially binary files, in the repository since
4150 git doesn't scale well for those. They will be in everyone's repo
4151 clones forever, forever making Chromium slower to clone and work
4152 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364153
Sam Maiera6e76d72022-02-11 21:43:504154 # Uploading files to cloud storage is not trivial so we don't want
4155 # to set the limit too low, but the upper limit for "normal" large
4156 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4157 # anything over 20 MB is exceptional.
4158 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364159
Sam Maiera6e76d72022-02-11 21:43:504160 too_large_files = []
4161 for f in input_api.AffectedFiles():
4162 # Check both added and modified files (but not deleted files).
4163 if f.Action() in ('A', 'M'):
4164 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4165 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4166 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364167
Sam Maiera6e76d72022-02-11 21:43:504168 if too_large_files:
4169 message = (
4170 'Do not commit large files to git since git scales badly for those.\n'
4171 +
4172 'Instead put the large files in cloud storage and use DEPS to\n' +
4173 'fetch them.\n' + '\n'.join(too_large_files))
4174 return [
4175 output_api.PresubmitError('Too large files found in commit',
4176 long_text=message + '\n')
4177 ]
4178 else:
4179 return []
Daniel Bratell93eb6c62019-04-29 20:13:364180
Max Morozb47503b2019-08-08 21:03:274181
Saagar Sanghavifceeaae2020-08-12 16:40:364182def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504183 """Checks specific for fuzz target sources."""
4184 EXPORTED_SYMBOLS = [
4185 'LLVMFuzzerInitialize',
4186 'LLVMFuzzerCustomMutator',
4187 'LLVMFuzzerCustomCrossOver',
4188 'LLVMFuzzerMutate',
4189 ]
Max Morozb47503b2019-08-08 21:03:274190
Sam Maiera6e76d72022-02-11 21:43:504191 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274192
Sam Maiera6e76d72022-02-11 21:43:504193 def FilterFile(affected_file):
4194 """Ignore libFuzzer source code."""
4195 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4196 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274197
Sam Maiera6e76d72022-02-11 21:43:504198 return input_api.FilterSourceFile(affected_file,
4199 files_to_check=[files_to_check],
4200 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274201
Sam Maiera6e76d72022-02-11 21:43:504202 files_with_missing_header = []
4203 for f in input_api.AffectedSourceFiles(FilterFile):
4204 contents = input_api.ReadFile(f, 'r')
4205 if REQUIRED_HEADER in contents:
4206 continue
Max Morozb47503b2019-08-08 21:03:274207
Sam Maiera6e76d72022-02-11 21:43:504208 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4209 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274210
Sam Maiera6e76d72022-02-11 21:43:504211 if not files_with_missing_header:
4212 return []
Max Morozb47503b2019-08-08 21:03:274213
Sam Maiera6e76d72022-02-11 21:43:504214 long_text = (
4215 'If you define any of the libFuzzer optional functions (%s), it is '
4216 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4217 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4218 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4219 'to access command line arguments passed to the fuzzer. Instead, prefer '
4220 'static initialization and shared resources as documented in '
4221 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4222 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4223 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274224
Sam Maiera6e76d72022-02-11 21:43:504225 return [
4226 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4227 REQUIRED_HEADER,
4228 items=files_with_missing_header,
4229 long_text=long_text)
4230 ]
Max Morozb47503b2019-08-08 21:03:274231
4232
Mohamed Heikald048240a2019-11-12 16:57:374233def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504234 """
4235 Warns authors who add images into the repo to make sure their images are
4236 optimized before committing.
4237 """
4238 images_added = False
4239 image_paths = []
4240 errors = []
4241 filter_lambda = lambda x: input_api.FilterSourceFile(
4242 x,
4243 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4244 DEFAULT_FILES_TO_SKIP),
4245 files_to_check=[r'.*\/(drawable|mipmap)'])
4246 for f in input_api.AffectedFiles(include_deletes=False,
4247 file_filter=filter_lambda):
4248 local_path = f.LocalPath().lower()
4249 if any(
4250 local_path.endswith(extension)
4251 for extension in _IMAGE_EXTENSIONS):
4252 images_added = True
4253 image_paths.append(f)
4254 if images_added:
4255 errors.append(
4256 output_api.PresubmitPromptWarning(
4257 'It looks like you are trying to commit some images. If these are '
4258 'non-test-only images, please make sure to read and apply the tips in '
4259 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4260 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4261 'FYI only and will not block your CL on the CQ.', image_paths))
4262 return errors
Mohamed Heikald048240a2019-11-12 16:57:374263
4264
Saagar Sanghavifceeaae2020-08-12 16:40:364265def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504266 """Groups upload checks that target android code."""
4267 results = []
4268 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4269 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4270 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4271 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4272 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4273 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4274 input_api, output_api))
4275 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4276 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4277 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4278 results.extend(_CheckNewImagesWarning(input_api, output_api))
4279 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4280 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4281 return results
4282
Becky Zhou7c69b50992018-12-10 19:37:574283
Saagar Sanghavifceeaae2020-08-12 16:40:364284def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504285 """Groups commit checks that target android code."""
4286 results = []
4287 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4288 return results
dgnaa68d5e2015-06-10 10:08:224289
Chris Hall59f8d0c72020-05-01 07:31:194290# TODO(chrishall): could we additionally match on any path owned by
4291# ui/accessibility/OWNERS ?
4292_ACCESSIBILITY_PATHS = (
4293 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4294 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4295 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4296 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4297 r"^content[\\/]browser[\\/]accessibility[\\/]",
4298 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4299 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4300 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4301 r"^ui[\\/]accessibility[\\/]",
4302 r"^ui[\\/]views[\\/]accessibility[\\/]",
4303)
4304
Saagar Sanghavifceeaae2020-08-12 16:40:364305def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504306 """Checks that commits to accessibility code contain an AX-Relnotes field in
4307 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194308
Sam Maiera6e76d72022-02-11 21:43:504309 def FileFilter(affected_file):
4310 paths = _ACCESSIBILITY_PATHS
4311 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194312
Sam Maiera6e76d72022-02-11 21:43:504313 # Only consider changes affecting accessibility paths.
4314 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4315 return []
Akihiro Ota08108e542020-05-20 15:30:534316
Sam Maiera6e76d72022-02-11 21:43:504317 # AX-Relnotes can appear in either the description or the footer.
4318 # When searching the description, require 'AX-Relnotes:' to appear at the
4319 # beginning of a line.
4320 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4321 description_has_relnotes = any(
4322 ax_regex.match(line)
4323 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194324
Sam Maiera6e76d72022-02-11 21:43:504325 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4326 'AX-Relnotes', [])
4327 if description_has_relnotes or footer_relnotes:
4328 return []
Chris Hall59f8d0c72020-05-01 07:31:194329
Sam Maiera6e76d72022-02-11 21:43:504330 # TODO(chrishall): link to Relnotes documentation in message.
4331 message = (
4332 "Missing 'AX-Relnotes:' field required for accessibility changes"
4333 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4334 "user-facing changes"
4335 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4336 "user-facing effects"
4337 "\n if this is confusing or annoying then please contact members "
4338 "of ui/accessibility/OWNERS.")
4339
4340 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224341
Mark Schillacie5a0be22022-01-19 00:38:394342
4343_ACCESSIBILITY_EVENTS_TEST_PATH = (
4344 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4345)
4346
4347_ACCESSIBILITY_TREE_TEST_PATH = (
4348 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4349 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4350 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4351 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4352)
4353
4354_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4355 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4356)
4357
4358_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444359 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394360)
4361
4362def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504363 """Checks that commits that include a newly added, renamed/moved, or deleted
4364 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4365 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394366
Sam Maiera6e76d72022-02-11 21:43:504367 def FilePathFilter(affected_file):
4368 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4369 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394370
Sam Maiera6e76d72022-02-11 21:43:504371 def AndroidFilePathFilter(affected_file):
4372 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4373 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394374
Sam Maiera6e76d72022-02-11 21:43:504375 # Only consider changes in the events test data path with html type.
4376 if not any(
4377 input_api.AffectedFiles(include_deletes=True,
4378 file_filter=FilePathFilter)):
4379 return []
Mark Schillacie5a0be22022-01-19 00:38:394380
Sam Maiera6e76d72022-02-11 21:43:504381 # If the commit contains any change to the Android test file, ignore.
4382 if any(
4383 input_api.AffectedFiles(include_deletes=True,
4384 file_filter=AndroidFilePathFilter)):
4385 return []
Mark Schillacie5a0be22022-01-19 00:38:394386
Sam Maiera6e76d72022-02-11 21:43:504387 # Only consider changes that are adding/renaming or deleting a file
4388 message = []
4389 for f in input_api.AffectedFiles(include_deletes=True,
4390 file_filter=FilePathFilter):
4391 if f.Action() == 'A' or f.Action() == 'D':
4392 message = (
4393 "It appears that you are adding, renaming or deleting"
4394 "\na dump_accessibility_events* test, but have not included"
4395 "\na corresponding change for Android."
4396 "\nPlease include (or remove) the test from:"
4397 "\n content/public/android/javatests/src/org/chromium/"
4398 "content/browser/accessibility/"
4399 "WebContentsAccessibilityEventsTest.java"
4400 "\nIf this message is confusing or annoying, please contact"
4401 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394402
Sam Maiera6e76d72022-02-11 21:43:504403 # If no message was set, return empty.
4404 if not len(message):
4405 return []
4406
4407 return [output_api.PresubmitPromptWarning(message)]
4408
Mark Schillacie5a0be22022-01-19 00:38:394409
4410def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504411 """Checks that commits that include a newly added, renamed/moved, or deleted
4412 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4413 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394414
Sam Maiera6e76d72022-02-11 21:43:504415 def FilePathFilter(affected_file):
4416 paths = _ACCESSIBILITY_TREE_TEST_PATH
4417 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394418
Sam Maiera6e76d72022-02-11 21:43:504419 def AndroidFilePathFilter(affected_file):
4420 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4421 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394422
Sam Maiera6e76d72022-02-11 21:43:504423 # Only consider changes in the various tree test data paths with html type.
4424 if not any(
4425 input_api.AffectedFiles(include_deletes=True,
4426 file_filter=FilePathFilter)):
4427 return []
Mark Schillacie5a0be22022-01-19 00:38:394428
Sam Maiera6e76d72022-02-11 21:43:504429 # If the commit contains any change to the Android test file, ignore.
4430 if any(
4431 input_api.AffectedFiles(include_deletes=True,
4432 file_filter=AndroidFilePathFilter)):
4433 return []
Mark Schillacie5a0be22022-01-19 00:38:394434
Sam Maiera6e76d72022-02-11 21:43:504435 # Only consider changes that are adding/renaming or deleting a file
4436 message = []
4437 for f in input_api.AffectedFiles(include_deletes=True,
4438 file_filter=FilePathFilter):
4439 if f.Action() == 'A' or f.Action() == 'D':
4440 message = (
4441 "It appears that you are adding, renaming or deleting"
4442 "\na dump_accessibility_tree* test, but have not included"
4443 "\na corresponding change for Android."
4444 "\nPlease include (or remove) the test from:"
4445 "\n content/public/android/javatests/src/org/chromium/"
4446 "content/browser/accessibility/"
4447 "WebContentsAccessibilityTreeTest.java"
4448 "\nIf this message is confusing or annoying, please contact"
4449 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394450
Sam Maiera6e76d72022-02-11 21:43:504451 # If no message was set, return empty.
4452 if not len(message):
4453 return []
4454
4455 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394456
4457
seanmccullough4a9356252021-04-08 19:54:094458# string pattern, sequence of strings to show when pattern matches,
4459# error flag. True if match is a presubmit error, otherwise it's a warning.
4460_NON_INCLUSIVE_TERMS = (
4461 (
4462 # Note that \b pattern in python re is pretty particular. In this
4463 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4464 # ...' will not. This may require some tweaking to catch these cases
4465 # without triggering a lot of false positives. Leaving it naive and
4466 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324467 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094468 (
4469 'Please don\'t use blacklist, whitelist, ' # nocheck
4470 'or slave in your', # nocheck
4471 'code and make every effort to use other terms. Using "// nocheck"',
4472 '"# nocheck" or "<!-- nocheck -->"',
4473 'at the end of the offending line will bypass this PRESUBMIT error',
4474 'but avoid using this whenever possible. Reach out to',
4475 '[email protected] if you have questions'),
4476 True),)
4477
Saagar Sanghavifceeaae2020-08-12 16:40:364478def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504479 """Checks common to both upload and commit."""
4480 results = []
Eric Boren6fd2b932018-01-25 15:05:084481 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504482 input_api.canned_checks.PanProjectChecks(
4483 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084484
Sam Maiera6e76d72022-02-11 21:43:504485 author = input_api.change.author_email
4486 if author and author not in _KNOWN_ROBOTS:
4487 results.extend(
4488 input_api.canned_checks.CheckAuthorizedAuthor(
4489 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244490
Sam Maiera6e76d72022-02-11 21:43:504491 results.extend(
4492 input_api.canned_checks.CheckChangeHasNoTabs(
4493 input_api,
4494 output_api,
4495 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4496 results.extend(
4497 input_api.RunTests(
4498 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174499
Bruce Dawsonc8054482022-03-28 15:33:374500 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504501 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374502 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504503 results.extend(
4504 input_api.RunTests(
4505 input_api.canned_checks.CheckDirMetadataFormat(
4506 input_api, output_api, dirmd_bin)))
4507 results.extend(
4508 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4509 input_api, output_api))
4510 results.extend(
4511 input_api.canned_checks.CheckNoNewMetadataInOwners(
4512 input_api, output_api))
4513 results.extend(
4514 input_api.canned_checks.CheckInclusiveLanguage(
4515 input_api,
4516 output_api,
4517 excluded_directories_relative_path=[
4518 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4519 ],
4520 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594521
Sam Maiera6e76d72022-02-11 21:43:504522 for f in input_api.AffectedFiles():
4523 path, name = input_api.os_path.split(f.LocalPath())
4524 if name == 'PRESUBMIT.py':
4525 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4526 path)
4527 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4528 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4529 # The PRESUBMIT.py file (and the directory containing it) might
4530 # have been affected by being moved or removed, so only try to
4531 # run the tests if they still exist.
4532 use_python3 = False
4533 with open(f.LocalPath()) as fp:
4534 use_python3 = any(
4535 line.startswith('USE_PYTHON3 = True')
4536 for line in fp.readlines())
4537
4538 results.extend(
4539 input_api.canned_checks.RunUnitTestsInDirectory(
4540 input_api,
4541 output_api,
4542 full_path,
4543 files_to_check=[r'^PRESUBMIT_test\.py$'],
4544 run_on_python2=not use_python3,
4545 run_on_python3=use_python3,
4546 skip_shebang_check=True))
4547 return results
[email protected]1f7b4172010-01-28 01:17:344548
[email protected]b337cb5b2011-01-23 21:24:054549
Saagar Sanghavifceeaae2020-08-12 16:40:364550def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504551 problems = [
4552 f.LocalPath() for f in input_api.AffectedFiles()
4553 if f.LocalPath().endswith(('.orig', '.rej'))
4554 ]
4555 # Cargo.toml.orig files are part of third-party crates downloaded from
4556 # crates.io and should be included.
4557 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4558 if problems:
4559 return [
4560 output_api.PresubmitError("Don't commit .rej and .orig files.",
4561 problems)
4562 ]
4563 else:
4564 return []
[email protected]b8079ae4a2012-12-05 19:56:494565
4566
Saagar Sanghavifceeaae2020-08-12 16:40:364567def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504568 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4569 macro_re = input_api.re.compile(
4570 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4571 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4572 input_api.re.MULTILINE)
4573 extension_re = input_api.re.compile(r'\.[a-z]+$')
4574 errors = []
4575 for f in input_api.AffectedFiles(include_deletes=False):
4576 if not f.LocalPath().endswith(
4577 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4578 continue
4579 found_line_number = None
4580 found_macro = None
4581 all_lines = input_api.ReadFile(f, 'r').splitlines()
4582 for line_num, line in enumerate(all_lines):
4583 match = macro_re.search(line)
4584 if match:
4585 found_line_number = line_num
4586 found_macro = match.group(2)
4587 break
4588 if not found_line_number:
4589 continue
Kent Tamura5a8755d2017-06-29 23:37:074590
Sam Maiera6e76d72022-02-11 21:43:504591 found_include_line = -1
4592 for line_num, line in enumerate(all_lines):
4593 if include_re.search(line):
4594 found_include_line = line_num
4595 break
4596 if found_include_line >= 0 and found_include_line < found_line_number:
4597 continue
Kent Tamura5a8755d2017-06-29 23:37:074598
Sam Maiera6e76d72022-02-11 21:43:504599 if not f.LocalPath().endswith('.h'):
4600 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4601 try:
4602 content = input_api.ReadFile(primary_header_path, 'r')
4603 if include_re.search(content):
4604 continue
4605 except IOError:
4606 pass
4607 errors.append('%s:%d %s macro is used without first including build/'
4608 'build_config.h.' %
4609 (f.LocalPath(), found_line_number, found_macro))
4610 if errors:
4611 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4612 return []
Kent Tamura5a8755d2017-06-29 23:37:074613
4614
Lei Zhang1c12a22f2021-05-12 11:28:454615def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504616 stl_include_re = input_api.re.compile(r'^#include\s+<('
4617 r'algorithm|'
4618 r'array|'
4619 r'limits|'
4620 r'list|'
4621 r'map|'
4622 r'memory|'
4623 r'queue|'
4624 r'set|'
4625 r'string|'
4626 r'unordered_map|'
4627 r'unordered_set|'
4628 r'utility|'
4629 r'vector)>')
4630 std_namespace_re = input_api.re.compile(r'std::')
4631 errors = []
4632 for f in input_api.AffectedFiles():
4633 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4634 continue
Lei Zhang1c12a22f2021-05-12 11:28:454635
Sam Maiera6e76d72022-02-11 21:43:504636 uses_std_namespace = False
4637 has_stl_include = False
4638 for line in f.NewContents():
4639 if has_stl_include and uses_std_namespace:
4640 break
Lei Zhang1c12a22f2021-05-12 11:28:454641
Sam Maiera6e76d72022-02-11 21:43:504642 if not has_stl_include and stl_include_re.search(line):
4643 has_stl_include = True
4644 continue
Lei Zhang1c12a22f2021-05-12 11:28:454645
Bruce Dawson4a5579a2022-04-08 17:11:364646 if not uses_std_namespace and (std_namespace_re.search(line)
4647 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504648 uses_std_namespace = True
4649 continue
Lei Zhang1c12a22f2021-05-12 11:28:454650
Sam Maiera6e76d72022-02-11 21:43:504651 if has_stl_include and not uses_std_namespace:
4652 errors.append(
4653 '%s: Includes STL header(s) but does not reference std::' %
4654 f.LocalPath())
4655 if errors:
4656 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4657 return []
Lei Zhang1c12a22f2021-05-12 11:28:454658
4659
Xiaohan Wang42d96c22022-01-20 17:23:114660def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504661 """Check for sensible looking, totally invalid OS macros."""
4662 preprocessor_statement = input_api.re.compile(r'^\s*#')
4663 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4664 results = []
4665 for lnum, line in f.ChangedContents():
4666 if preprocessor_statement.search(line):
4667 for match in os_macro.finditer(line):
4668 results.append(
4669 ' %s:%d: %s' %
4670 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4671 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4672 return results
[email protected]b00342e7f2013-03-26 16:21:544673
4674
Xiaohan Wang42d96c22022-01-20 17:23:114675def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504676 """Check all affected files for invalid OS macros."""
4677 bad_macros = []
4678 for f in input_api.AffectedSourceFiles(None):
4679 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4680 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544681
Sam Maiera6e76d72022-02-11 21:43:504682 if not bad_macros:
4683 return []
[email protected]b00342e7f2013-03-26 16:21:544684
Sam Maiera6e76d72022-02-11 21:43:504685 return [
4686 output_api.PresubmitError(
4687 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4688 'defined in build_config.h):', bad_macros)
4689 ]
[email protected]b00342e7f2013-03-26 16:21:544690
lliabraa35bab3932014-10-01 12:16:444691
4692def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504693 """Check all affected files for invalid "if defined" macros."""
4694 ALWAYS_DEFINED_MACROS = (
4695 "TARGET_CPU_PPC",
4696 "TARGET_CPU_PPC64",
4697 "TARGET_CPU_68K",
4698 "TARGET_CPU_X86",
4699 "TARGET_CPU_ARM",
4700 "TARGET_CPU_MIPS",
4701 "TARGET_CPU_SPARC",
4702 "TARGET_CPU_ALPHA",
4703 "TARGET_IPHONE_SIMULATOR",
4704 "TARGET_OS_EMBEDDED",
4705 "TARGET_OS_IPHONE",
4706 "TARGET_OS_MAC",
4707 "TARGET_OS_UNIX",
4708 "TARGET_OS_WIN32",
4709 )
4710 ifdef_macro = input_api.re.compile(
4711 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4712 results = []
4713 for lnum, line in f.ChangedContents():
4714 for match in ifdef_macro.finditer(line):
4715 if match.group(1) in ALWAYS_DEFINED_MACROS:
4716 always_defined = ' %s is always defined. ' % match.group(1)
4717 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4718 results.append(
4719 ' %s:%d %s\n\t%s' %
4720 (f.LocalPath(), lnum, always_defined, did_you_mean))
4721 return results
lliabraa35bab3932014-10-01 12:16:444722
4723
Saagar Sanghavifceeaae2020-08-12 16:40:364724def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504725 """Check all affected files for invalid "if defined" macros."""
4726 bad_macros = []
4727 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4728 for f in input_api.AffectedFiles():
4729 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4730 continue
4731 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4732 bad_macros.extend(
4733 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444734
Sam Maiera6e76d72022-02-11 21:43:504735 if not bad_macros:
4736 return []
lliabraa35bab3932014-10-01 12:16:444737
Sam Maiera6e76d72022-02-11 21:43:504738 return [
4739 output_api.PresubmitError(
4740 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4741 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4742 bad_macros)
4743 ]
lliabraa35bab3932014-10-01 12:16:444744
4745
Saagar Sanghavifceeaae2020-08-12 16:40:364746def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504747 """Check for same IPC rules described in
4748 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4749 """
4750 base_pattern = r'IPC_ENUM_TRAITS\('
4751 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4752 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044753
Sam Maiera6e76d72022-02-11 21:43:504754 problems = []
4755 for f in input_api.AffectedSourceFiles(None):
4756 local_path = f.LocalPath()
4757 if not local_path.endswith('.h'):
4758 continue
4759 for line_number, line in f.ChangedContents():
4760 if inclusion_pattern.search(
4761 line) and not comment_pattern.search(line):
4762 problems.append('%s:%d\n %s' %
4763 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044764
Sam Maiera6e76d72022-02-11 21:43:504765 if problems:
4766 return [
4767 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4768 problems)
4769 ]
4770 else:
4771 return []
mlamouria82272622014-09-16 18:45:044772
[email protected]b00342e7f2013-03-26 16:21:544773
Saagar Sanghavifceeaae2020-08-12 16:40:364774def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504775 """Check to make sure no files being submitted have long paths.
4776 This causes issues on Windows.
4777 """
4778 problems = []
4779 for f in input_api.AffectedTestableFiles():
4780 local_path = f.LocalPath()
4781 # Windows has a path limit of 260 characters. Limit path length to 200 so
4782 # that we have some extra for the prefix on dev machines and the bots.
4783 if len(local_path) > 200:
4784 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054785
Sam Maiera6e76d72022-02-11 21:43:504786 if problems:
4787 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4788 else:
4789 return []
Stephen Martinis97a394142018-06-07 23:06:054790
4791
Saagar Sanghavifceeaae2020-08-12 16:40:364792def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504793 """Check that header files have proper guards against multiple inclusion.
4794 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364795 should include the string "no-include-guard-because-multiply-included" or
4796 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504797 """
Daniel Bratell8ba52722018-03-02 16:06:144798
Sam Maiera6e76d72022-02-11 21:43:504799 def is_chromium_header_file(f):
4800 # We only check header files under the control of the Chromium
4801 # project. That is, those outside third_party apart from
4802 # third_party/blink.
4803 # We also exclude *_message_generator.h headers as they use
4804 # include guards in a special, non-typical way.
4805 file_with_path = input_api.os_path.normpath(f.LocalPath())
4806 return (file_with_path.endswith('.h')
4807 and not file_with_path.endswith('_message_generator.h')
4808 and (not file_with_path.startswith('third_party')
4809 or file_with_path.startswith(
4810 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144811
Sam Maiera6e76d72022-02-11 21:43:504812 def replace_special_with_underscore(string):
4813 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144814
Sam Maiera6e76d72022-02-11 21:43:504815 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144816
Sam Maiera6e76d72022-02-11 21:43:504817 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4818 guard_name = None
4819 guard_line_number = None
4820 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144821
Sam Maiera6e76d72022-02-11 21:43:504822 file_with_path = input_api.os_path.normpath(f.LocalPath())
4823 base_file_name = input_api.os_path.splitext(
4824 input_api.os_path.basename(file_with_path))[0]
4825 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144826
Sam Maiera6e76d72022-02-11 21:43:504827 expected_guard = replace_special_with_underscore(
4828 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144829
Sam Maiera6e76d72022-02-11 21:43:504830 # For "path/elem/file_name.h" we should really only accept
4831 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4832 # are too many (1000+) files with slight deviations from the
4833 # coding style. The most important part is that the include guard
4834 # is there, and that it's unique, not the name so this check is
4835 # forgiving for existing files.
4836 #
4837 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144838
Sam Maiera6e76d72022-02-11 21:43:504839 guard_name_pattern_list = [
4840 # Anything with the right suffix (maybe with an extra _).
4841 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144842
Sam Maiera6e76d72022-02-11 21:43:504843 # To cover include guards with old Blink style.
4844 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144845
Sam Maiera6e76d72022-02-11 21:43:504846 # Anything including the uppercase name of the file.
4847 r'\w*' + input_api.re.escape(
4848 replace_special_with_underscore(upper_base_file_name)) +
4849 r'\w*',
4850 ]
4851 guard_name_pattern = '|'.join(guard_name_pattern_list)
4852 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4853 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144854
Sam Maiera6e76d72022-02-11 21:43:504855 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364856 if ('no-include-guard-because-multiply-included' in line
4857 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504858 guard_name = 'DUMMY' # To not trigger check outside the loop.
4859 break
Daniel Bratell8ba52722018-03-02 16:06:144860
Sam Maiera6e76d72022-02-11 21:43:504861 if guard_name is None:
4862 match = guard_pattern.match(line)
4863 if match:
4864 guard_name = match.group(1)
4865 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144866
Sam Maiera6e76d72022-02-11 21:43:504867 # We allow existing files to use include guards whose names
4868 # don't match the chromium style guide, but new files should
4869 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494870 if guard_name != expected_guard:
4871 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504872 errors.append(
4873 output_api.PresubmitPromptWarning(
4874 'Header using the wrong include guard name %s'
4875 % guard_name, [
4876 '%s:%d' %
4877 (f.LocalPath(), line_number + 1)
4878 ], 'Expected: %r\nFound: %r' %
4879 (expected_guard, guard_name)))
4880 else:
4881 # The line after #ifndef should have a #define of the same name.
4882 if line_number == guard_line_number + 1:
4883 expected_line = '#define %s' % guard_name
4884 if line != expected_line:
4885 errors.append(
4886 output_api.PresubmitPromptWarning(
4887 'Missing "%s" for include guard' %
4888 expected_line,
4889 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4890 'Expected: %r\nGot: %r' %
4891 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144892
Sam Maiera6e76d72022-02-11 21:43:504893 if not seen_guard_end and line == '#endif // %s' % guard_name:
4894 seen_guard_end = True
4895 elif seen_guard_end:
4896 if line.strip() != '':
4897 errors.append(
4898 output_api.PresubmitPromptWarning(
4899 'Include guard %s not covering the whole file'
4900 % (guard_name), [f.LocalPath()]))
4901 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144902
Sam Maiera6e76d72022-02-11 21:43:504903 if guard_name is None:
4904 errors.append(
4905 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494906 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504907 'Recommended name: %s\n'
4908 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364909 '"no-include-guard-because-multiply-included" or\n'
4910 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504911 % (f.LocalPath(), expected_guard)))
4912
4913 return errors
Daniel Bratell8ba52722018-03-02 16:06:144914
4915
Saagar Sanghavifceeaae2020-08-12 16:40:364916def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504917 """Check source code and known ascii text files for Windows style line
4918 endings.
4919 """
Bruce Dawson5efbdc652022-04-11 19:29:514920 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234921
Sam Maiera6e76d72022-02-11 21:43:504922 file_inclusion_pattern = (known_text_files,
4923 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4924 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:234925
Sam Maiera6e76d72022-02-11 21:43:504926 problems = []
4927 source_file_filter = lambda f: input_api.FilterSourceFile(
4928 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
4929 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:514930 # Ignore test files that contain crlf intentionally.
4931 if f.LocalPath().endswith('crlf.txt'):
4932 continue
Sam Maiera6e76d72022-02-11 21:43:504933 include_file = False
4934 for line in input_api.ReadFile(f, 'r').splitlines(True):
4935 if line.endswith('\r\n'):
4936 include_file = True
4937 if include_file:
4938 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234939
Sam Maiera6e76d72022-02-11 21:43:504940 if problems:
4941 return [
4942 output_api.PresubmitPromptWarning(
4943 'Are you sure that you want '
4944 'these files to contain Windows style line endings?\n' +
4945 '\n'.join(problems))
4946 ]
mostynbb639aca52015-01-07 20:31:234947
Sam Maiera6e76d72022-02-11 21:43:504948 return []
4949
mostynbb639aca52015-01-07 20:31:234950
Evan Stade6cfc964c12021-05-18 20:21:164951def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504952 """Check that .icon files (which are fragments of C++) have license headers.
4953 """
Evan Stade6cfc964c12021-05-18 20:21:164954
Sam Maiera6e76d72022-02-11 21:43:504955 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:164956
Sam Maiera6e76d72022-02-11 21:43:504957 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4958 return input_api.canned_checks.CheckLicense(input_api,
4959 output_api,
4960 source_file_filter=icons)
4961
Evan Stade6cfc964c12021-05-18 20:21:164962
Jose Magana2b456f22021-03-09 23:26:404963def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504964 """Check source code for use of Chrome App technologies being
4965 deprecated.
4966 """
Jose Magana2b456f22021-03-09 23:26:404967
Sam Maiera6e76d72022-02-11 21:43:504968 def _CheckForDeprecatedTech(input_api,
4969 output_api,
4970 detection_list,
4971 files_to_check=None,
4972 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:404973
Sam Maiera6e76d72022-02-11 21:43:504974 if (files_to_check or files_to_skip):
4975 source_file_filter = lambda f: input_api.FilterSourceFile(
4976 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
4977 else:
4978 source_file_filter = None
4979
4980 problems = []
4981
4982 for f in input_api.AffectedSourceFiles(source_file_filter):
4983 if f.Action() == 'D':
4984 continue
4985 for _, line in f.ChangedContents():
4986 if any(detect in line for detect in detection_list):
4987 problems.append(f.LocalPath())
4988
4989 return problems
4990
4991 # to avoid this presubmit script triggering warnings
4992 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:404993
4994 problems = []
4995
Sam Maiera6e76d72022-02-11 21:43:504996 # NMF: any files with extensions .nmf or NMF
4997 _NMF_FILES = r'\.(nmf|NMF)$'
4998 problems += _CheckForDeprecatedTech(
4999 input_api,
5000 output_api,
5001 detection_list=[''], # any change to the file will trigger warning
5002 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405003
Sam Maiera6e76d72022-02-11 21:43:505004 # MANIFEST: any manifest.json that in its diff includes "app":
5005 _MANIFEST_FILES = r'(manifest\.json)$'
5006 problems += _CheckForDeprecatedTech(
5007 input_api,
5008 output_api,
5009 detection_list=['"app":'],
5010 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405011
Sam Maiera6e76d72022-02-11 21:43:505012 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5013 problems += _CheckForDeprecatedTech(
5014 input_api,
5015 output_api,
5016 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5017 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405018
Sam Maiera6e76d72022-02-11 21:43:505019 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5020 problems += _CheckForDeprecatedTech(
5021 input_api,
5022 output_api,
5023 detection_list=['#include "ppapi', '#include <ppapi'],
5024 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5025 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5026 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405027
Sam Maiera6e76d72022-02-11 21:43:505028 if problems:
5029 return [
5030 output_api.PresubmitPromptWarning(
5031 'You are adding/modifying code'
5032 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5033 ' PNaCl, PPAPI). See this blog post for more details:\n'
5034 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5035 'and this documentation for options to replace these technologies:\n'
5036 'https://developer.chrome.com/docs/apps/migration/\n' +
5037 '\n'.join(problems))
5038 ]
Jose Magana2b456f22021-03-09 23:26:405039
Sam Maiera6e76d72022-02-11 21:43:505040 return []
Jose Magana2b456f22021-03-09 23:26:405041
mostynbb639aca52015-01-07 20:31:235042
Saagar Sanghavifceeaae2020-08-12 16:40:365043def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505044 """Checks that all source files use SYSLOG properly."""
5045 syslog_files = []
5046 for f in input_api.AffectedSourceFiles(src_file_filter):
5047 for line_number, line in f.ChangedContents():
5048 if 'SYSLOG' in line:
5049 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565050
Sam Maiera6e76d72022-02-11 21:43:505051 if syslog_files:
5052 return [
5053 output_api.PresubmitPromptWarning(
5054 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5055 ' calls.\nFiles to check:\n',
5056 items=syslog_files)
5057 ]
5058 return []
pastarmovj89f7ee12016-09-20 14:58:135059
5060
[email protected]1f7b4172010-01-28 01:17:345061def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505062 if input_api.version < [2, 0, 0]:
5063 return [
5064 output_api.PresubmitError(
5065 "Your depot_tools is out of date. "
5066 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5067 "but your version is %d.%d.%d" % tuple(input_api.version))
5068 ]
5069 results = []
5070 results.extend(
5071 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5072 return results
[email protected]ca8d1982009-02-19 16:33:125073
5074
5075def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505076 if input_api.version < [2, 0, 0]:
5077 return [
5078 output_api.PresubmitError(
5079 "Your depot_tools is out of date. "
5080 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5081 "but your version is %d.%d.%d" % tuple(input_api.version))
5082 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365083
Sam Maiera6e76d72022-02-11 21:43:505084 results = []
5085 # Make sure the tree is 'open'.
5086 results.extend(
5087 input_api.canned_checks.CheckTreeIsOpen(
5088 input_api,
5089 output_api,
5090 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275091
Sam Maiera6e76d72022-02-11 21:43:505092 results.extend(
5093 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5094 results.extend(
5095 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5096 results.extend(
5097 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5098 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505099 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145100
5101
Saagar Sanghavifceeaae2020-08-12 16:40:365102def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505103 """Check string ICU syntax validity and if translation screenshots exist."""
5104 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5105 # footer is set to true.
5106 git_footers = input_api.change.GitFootersFromDescription()
5107 skip_screenshot_check_footer = [
5108 footer.lower() for footer in git_footers.get(
5109 u'Skip-Translation-Screenshots-Check', [])
5110 ]
5111 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025112
Sam Maiera6e76d72022-02-11 21:43:505113 import os
5114 import re
5115 import sys
5116 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145117
Sam Maiera6e76d72022-02-11 21:43:505118 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5119 if (f.Action() == 'A' or f.Action() == 'M'))
5120 removed_paths = set(f.LocalPath()
5121 for f in input_api.AffectedFiles(include_deletes=True)
5122 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123
Sam Maiera6e76d72022-02-11 21:43:505124 affected_grds = [
5125 f for f in input_api.AffectedFiles()
5126 if f.LocalPath().endswith(('.grd', '.grdp'))
5127 ]
5128 affected_grds = [
5129 f for f in affected_grds if not 'testdata' in f.LocalPath()
5130 ]
5131 if not affected_grds:
5132 return []
meacer8c0d3832019-12-26 21:46:165133
Sam Maiera6e76d72022-02-11 21:43:505134 affected_png_paths = [
5135 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5136 if (f.LocalPath().endswith('.png'))
5137 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145138
Sam Maiera6e76d72022-02-11 21:43:505139 # Check for screenshots. Developers can upload screenshots using
5140 # tools/translation/upload_screenshots.py which finds and uploads
5141 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5142 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5143 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5144 #
5145 # The logic here is as follows:
5146 #
5147 # - If the CL has a .png file under the screenshots directory for a grd
5148 # file, warn the developer. Actual images should never be checked into the
5149 # Chrome repo.
5150 #
5151 # - If the CL contains modified or new messages in grd files and doesn't
5152 # contain the corresponding .sha1 files, warn the developer to add images
5153 # and upload them via tools/translation/upload_screenshots.py.
5154 #
5155 # - If the CL contains modified or new messages in grd files and the
5156 # corresponding .sha1 files, everything looks good.
5157 #
5158 # - If the CL contains removed messages in grd files but the corresponding
5159 # .sha1 files aren't removed, warn the developer to remove them.
5160 unnecessary_screenshots = []
5161 missing_sha1 = []
5162 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145163
Sam Maiera6e76d72022-02-11 21:43:505164 # This checks verifies that the ICU syntax of messages this CL touched is
5165 # valid, and reports any found syntax errors.
5166 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5167 # without developers being aware of them. Later on, such ICU syntax errors
5168 # break message extraction for translation, hence would block Chromium
5169 # translations until they are fixed.
5170 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145171
Sam Maiera6e76d72022-02-11 21:43:505172 def _CheckScreenshotAdded(screenshots_dir, message_id):
5173 sha1_path = input_api.os_path.join(screenshots_dir,
5174 message_id + '.png.sha1')
5175 if sha1_path not in new_or_added_paths:
5176 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145177
Sam Maiera6e76d72022-02-11 21:43:505178 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5179 sha1_path = input_api.os_path.join(screenshots_dir,
5180 message_id + '.png.sha1')
5181 if input_api.os_path.exists(
5182 sha1_path) and sha1_path not in removed_paths:
5183 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145184
Sam Maiera6e76d72022-02-11 21:43:505185 def _ValidateIcuSyntax(text, level, signatures):
5186 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145187
Sam Maiera6e76d72022-02-11 21:43:505188 Check if text looks similar to ICU and checks for ICU syntax correctness
5189 in this case. Reports various issues with ICU syntax and values of
5190 variants. Supports checking of nested messages. Accumulate information of
5191 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265192
Sam Maiera6e76d72022-02-11 21:43:505193 Args:
5194 text: a string to check.
5195 level: a number of current nesting level.
5196 signatures: an accumulator, a list of tuple of (level, variable,
5197 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265198
Sam Maiera6e76d72022-02-11 21:43:505199 Returns:
5200 None if a string is not ICU or no issue detected.
5201 A tuple of (message, start index, end index) if an issue detected.
5202 """
5203 valid_types = {
5204 'plural': (frozenset(
5205 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5206 'other']), frozenset(['=1', 'other'])),
5207 'selectordinal': (frozenset(
5208 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5209 'other']), frozenset(['one', 'other'])),
5210 'select': (frozenset(), frozenset(['other'])),
5211 }
Rainhard Findlingfc31844c52020-05-15 09:58:265212
Sam Maiera6e76d72022-02-11 21:43:505213 # Check if the message looks like an attempt to use ICU
5214 # plural. If yes - check if its syntax strictly matches ICU format.
5215 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5216 text)
5217 if not like:
5218 signatures.append((level, None, None, None))
5219 return
Rainhard Findlingfc31844c52020-05-15 09:58:265220
Sam Maiera6e76d72022-02-11 21:43:505221 # Check for valid prefix and suffix
5222 m = re.match(
5223 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5224 r'(plural|selectordinal|select),\s*'
5225 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5226 if not m:
5227 return (('This message looks like an ICU plural, '
5228 'but does not follow ICU syntax.'), like.start(),
5229 like.end())
5230 starting, variable, kind, variant_pairs = m.groups()
5231 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5232 m.start(4))
5233 if depth:
5234 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5235 len(text))
5236 first = text[0]
5237 ending = text[last_pos:]
5238 if not starting:
5239 return ('Invalid ICU format. No initial opening bracket',
5240 last_pos - 1, last_pos)
5241 if not ending or '}' not in ending:
5242 return ('Invalid ICU format. No final closing bracket',
5243 last_pos - 1, last_pos)
5244 elif first != '{':
5245 return ((
5246 'Invalid ICU format. Extra characters at the start of a complex '
5247 'message (go/icu-message-migration): "%s"') % starting, 0,
5248 len(starting))
5249 elif ending != '}':
5250 return ((
5251 'Invalid ICU format. Extra characters at the end of a complex '
5252 'message (go/icu-message-migration): "%s"') % ending,
5253 last_pos - 1, len(text) - 1)
5254 if kind not in valid_types:
5255 return (('Unknown ICU message type %s. '
5256 'Valid types are: plural, select, selectordinal') % kind,
5257 0, 0)
5258 known, required = valid_types[kind]
5259 defined_variants = set()
5260 for variant, variant_range, value, value_range in variants:
5261 start, end = variant_range
5262 if variant in defined_variants:
5263 return ('Variant "%s" is defined more than once' % variant,
5264 start, end)
5265 elif known and variant not in known:
5266 return ('Variant "%s" is not valid for %s message' %
5267 (variant, kind), start, end)
5268 defined_variants.add(variant)
5269 # Check for nested structure
5270 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5271 if res:
5272 return (res[0], res[1] + value_range[0] + 1,
5273 res[2] + value_range[0] + 1)
5274 missing = required - defined_variants
5275 if missing:
5276 return ('Required variants missing: %s' % ', '.join(missing), 0,
5277 len(text))
5278 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265279
Sam Maiera6e76d72022-02-11 21:43:505280 def _ParseIcuVariants(text, offset=0):
5281 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265282
Sam Maiera6e76d72022-02-11 21:43:505283 Builds a tuple of variant names and values, as well as
5284 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265285
Sam Maiera6e76d72022-02-11 21:43:505286 Args:
5287 text: a string to parse
5288 offset: additional offset to add to positions in the text to get correct
5289 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265290
Sam Maiera6e76d72022-02-11 21:43:505291 Returns:
5292 List of tuples, each tuple consist of four fields: variant name,
5293 variant name span (tuple of two integers), variant value, value
5294 span (tuple of two integers).
5295 """
5296 depth, start, end = 0, -1, -1
5297 variants = []
5298 key = None
5299 for idx, char in enumerate(text):
5300 if char == '{':
5301 if not depth:
5302 start = idx
5303 chunk = text[end + 1:start]
5304 key = chunk.strip()
5305 pos = offset + end + 1 + chunk.find(key)
5306 span = (pos, pos + len(key))
5307 depth += 1
5308 elif char == '}':
5309 if not depth:
5310 return variants, depth, offset + idx
5311 depth -= 1
5312 if not depth:
5313 end = idx
5314 variants.append((key, span, text[start:end + 1],
5315 (offset + start, offset + end + 1)))
5316 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265317
Sam Maiera6e76d72022-02-11 21:43:505318 try:
5319 old_sys_path = sys.path
5320 sys.path = sys.path + [
5321 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5322 'translation')
5323 ]
5324 from helper import grd_helper
5325 finally:
5326 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265327
Sam Maiera6e76d72022-02-11 21:43:505328 for f in affected_grds:
5329 file_path = f.LocalPath()
5330 old_id_to_msg_map = {}
5331 new_id_to_msg_map = {}
5332 # Note that this code doesn't check if the file has been deleted. This is
5333 # OK because it only uses the old and new file contents and doesn't load
5334 # the file via its path.
5335 # It's also possible that a file's content refers to a renamed or deleted
5336 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5337 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5338 # .grdp files.
5339 if file_path.endswith('.grdp'):
5340 if f.OldContents():
5341 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5342 '\n'.join(f.OldContents()))
5343 if f.NewContents():
5344 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5345 '\n'.join(f.NewContents()))
5346 else:
5347 file_dir = input_api.os_path.dirname(file_path) or '.'
5348 if f.OldContents():
5349 old_id_to_msg_map = grd_helper.GetGrdMessages(
5350 StringIO('\n'.join(f.OldContents())), file_dir)
5351 if f.NewContents():
5352 new_id_to_msg_map = grd_helper.GetGrdMessages(
5353 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265354
Sam Maiera6e76d72022-02-11 21:43:505355 grd_name, ext = input_api.os_path.splitext(
5356 input_api.os_path.basename(file_path))
5357 screenshots_dir = input_api.os_path.join(
5358 input_api.os_path.dirname(file_path),
5359 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265360
Sam Maiera6e76d72022-02-11 21:43:505361 # Compute added, removed and modified message IDs.
5362 old_ids = set(old_id_to_msg_map)
5363 new_ids = set(new_id_to_msg_map)
5364 added_ids = new_ids - old_ids
5365 removed_ids = old_ids - new_ids
5366 modified_ids = set([])
5367 for key in old_ids.intersection(new_ids):
5368 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5369 new_id_to_msg_map[key].ContentsAsXml('', True)):
5370 # The message content itself changed. Require an updated screenshot.
5371 modified_ids.add(key)
5372 elif old_id_to_msg_map[key].attrs['meaning'] != \
5373 new_id_to_msg_map[key].attrs['meaning']:
5374 # The message meaning changed. Ensure there is a screenshot for it.
5375 sha1_path = input_api.os_path.join(screenshots_dir,
5376 key + '.png.sha1')
5377 if sha1_path not in new_or_added_paths and not \
5378 input_api.os_path.exists(sha1_path):
5379 # There is neither a previous screenshot nor is a new one added now.
5380 # Require a screenshot.
5381 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145382
Sam Maiera6e76d72022-02-11 21:43:505383 if run_screenshot_check:
5384 # Check the screenshot directory for .png files. Warn if there is any.
5385 for png_path in affected_png_paths:
5386 if png_path.startswith(screenshots_dir):
5387 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145388
Sam Maiera6e76d72022-02-11 21:43:505389 for added_id in added_ids:
5390 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095391
Sam Maiera6e76d72022-02-11 21:43:505392 for modified_id in modified_ids:
5393 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145394
Sam Maiera6e76d72022-02-11 21:43:505395 for removed_id in removed_ids:
5396 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5397
5398 # Check new and changed strings for ICU syntax errors.
5399 for key in added_ids.union(modified_ids):
5400 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5401 err = _ValidateIcuSyntax(msg, 0, [])
5402 if err is not None:
5403 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5404
5405 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265406 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505407 if unnecessary_screenshots:
5408 results.append(
5409 output_api.PresubmitError(
5410 'Do not include actual screenshots in the changelist. Run '
5411 'tools/translate/upload_screenshots.py to upload them instead:',
5412 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145413
Sam Maiera6e76d72022-02-11 21:43:505414 if missing_sha1:
5415 results.append(
5416 output_api.PresubmitError(
5417 'You are adding or modifying UI strings.\n'
5418 'To ensure the best translations, take screenshots of the relevant UI '
5419 '(https://g.co/chrome/translation) and add these files to your '
5420 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145421
Sam Maiera6e76d72022-02-11 21:43:505422 if unnecessary_sha1_files:
5423 results.append(
5424 output_api.PresubmitError(
5425 'You removed strings associated with these files. Remove:',
5426 sorted(unnecessary_sha1_files)))
5427 else:
5428 results.append(
5429 output_api.PresubmitPromptOrNotify('Skipping translation '
5430 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145431
Sam Maiera6e76d72022-02-11 21:43:505432 if icu_syntax_errors:
5433 results.append(
5434 output_api.PresubmitPromptWarning(
5435 'ICU syntax errors were found in the following strings (problems or '
5436 'feedback? Contact [email protected]):',
5437 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265438
Sam Maiera6e76d72022-02-11 21:43:505439 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125440
5441
Saagar Sanghavifceeaae2020-08-12 16:40:365442def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125443 repo_root=None,
5444 translation_expectations_path=None,
5445 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505446 import sys
5447 affected_grds = [
5448 f for f in input_api.AffectedFiles()
5449 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5450 ]
5451 if not affected_grds:
5452 return []
5453
5454 try:
5455 old_sys_path = sys.path
5456 sys.path = sys.path + [
5457 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5458 'translation')
5459 ]
5460 from helper import git_helper
5461 from helper import translation_helper
5462 finally:
5463 sys.path = old_sys_path
5464
5465 # Check that translation expectations can be parsed and we can get a list of
5466 # translatable grd files. |repo_root| and |translation_expectations_path| are
5467 # only passed by tests.
5468 if not repo_root:
5469 repo_root = input_api.PresubmitLocalPath()
5470 if not translation_expectations_path:
5471 translation_expectations_path = input_api.os_path.join(
5472 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5473 if not grd_files:
5474 grd_files = git_helper.list_grds_in_repository(repo_root)
5475
5476 # Ignore bogus grd files used only for testing
5477 # ui/webui/resoucres/tools/generate_grd.py.
5478 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5479 'tests')
5480 grd_files = [p for p in grd_files if ignore_path not in p]
5481
5482 try:
5483 translation_helper.get_translatable_grds(
5484 repo_root, grd_files, translation_expectations_path)
5485 except Exception as e:
5486 return [
5487 output_api.PresubmitNotifyResult(
5488 'Failed to get a list of translatable grd files. This happens when:\n'
5489 ' - One of the modified grd or grdp files cannot be parsed or\n'
5490 ' - %s is not updated.\n'
5491 'Stack:\n%s' % (translation_expectations_path, str(e)))
5492 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125493 return []
5494
Ken Rockotc31f4832020-05-29 18:58:515495
Saagar Sanghavifceeaae2020-08-12 16:40:365496def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505497 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5498 changed_mojoms = input_api.AffectedFiles(
5499 include_deletes=True,
5500 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525501
Sam Maiera6e76d72022-02-11 21:43:505502 if not changed_mojoms:
5503 return []
5504
5505 delta = []
5506 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505507 delta.append({
5508 'filename': mojom.LocalPath(),
5509 'old': '\n'.join(mojom.OldContents()) or None,
5510 'new': '\n'.join(mojom.NewContents()) or None,
5511 })
5512
5513 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215514 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505515 input_api.os_path.join(
5516 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5517 'check_stable_mojom_compatibility.py'), '--src-root',
5518 input_api.PresubmitLocalPath()
5519 ],
5520 stdin=input_api.subprocess.PIPE,
5521 stdout=input_api.subprocess.PIPE,
5522 stderr=input_api.subprocess.PIPE,
5523 universal_newlines=True)
5524 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5525 if process.returncode:
5526 return [
5527 output_api.PresubmitError(
5528 'One or more [Stable] mojom definitions appears to have been changed '
5529 'in a way that is not backward-compatible.',
5530 long_text=error)
5531 ]
Erik Staabc734cd7a2021-11-23 03:11:525532 return []
5533
Dominic Battre645d42342020-12-04 16:14:105534def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505535 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105536
Sam Maiera6e76d72022-02-11 21:43:505537 def FilterFile(affected_file):
5538 """Accept only .cc files and the like."""
5539 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5540 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5541 input_api.DEFAULT_FILES_TO_SKIP)
5542 return input_api.FilterSourceFile(
5543 affected_file,
5544 files_to_check=file_inclusion_pattern,
5545 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105546
Sam Maiera6e76d72022-02-11 21:43:505547 def ModifiedLines(affected_file):
5548 """Returns a list of tuples (line number, line text) of added and removed
5549 lines.
Dominic Battre645d42342020-12-04 16:14:105550
Sam Maiera6e76d72022-02-11 21:43:505551 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105552
Sam Maiera6e76d72022-02-11 21:43:505553 This relies on the scm diff output describing each changed code section
5554 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105555
Sam Maiera6e76d72022-02-11 21:43:505556 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5557 """
5558 line_num = 0
5559 modified_lines = []
5560 for line in affected_file.GenerateScmDiff().splitlines():
5561 # Extract <new line num> of the patch fragment (see format above).
5562 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5563 line)
5564 if m:
5565 line_num = int(m.groups(1)[0])
5566 continue
5567 if ((line.startswith('+') and not line.startswith('++'))
5568 or (line.startswith('-') and not line.startswith('--'))):
5569 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105570
Sam Maiera6e76d72022-02-11 21:43:505571 if not line.startswith('-'):
5572 line_num += 1
5573 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105574
Sam Maiera6e76d72022-02-11 21:43:505575 def FindLineWith(lines, needle):
5576 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105577
Sam Maiera6e76d72022-02-11 21:43:505578 If 0 or >1 lines contain `needle`, -1 is returned.
5579 """
5580 matching_line_numbers = [
5581 # + 1 for 1-based counting of line numbers.
5582 i + 1 for i, line in enumerate(lines) if needle in line
5583 ]
5584 return matching_line_numbers[0] if len(
5585 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105586
Sam Maiera6e76d72022-02-11 21:43:505587 def ModifiedPrefMigration(affected_file):
5588 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5589 # Determine first and last lines of MigrateObsolete.*Pref functions.
5590 new_contents = affected_file.NewContents()
5591 range_1 = (FindLineWith(new_contents,
5592 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5593 FindLineWith(new_contents,
5594 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5595 range_2 = (FindLineWith(new_contents,
5596 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5597 FindLineWith(new_contents,
5598 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5599 if (-1 in range_1 + range_2):
5600 raise Exception(
5601 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5602 )
Dominic Battre645d42342020-12-04 16:14:105603
Sam Maiera6e76d72022-02-11 21:43:505604 # Check whether any of the modified lines are part of the
5605 # MigrateObsolete.*Pref functions.
5606 for line_nr, line in ModifiedLines(affected_file):
5607 if (range_1[0] <= line_nr <= range_1[1]
5608 or range_2[0] <= line_nr <= range_2[1]):
5609 return True
5610 return False
Dominic Battre645d42342020-12-04 16:14:105611
Sam Maiera6e76d72022-02-11 21:43:505612 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5613 browser_prefs_file_pattern = input_api.re.compile(
5614 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105615
Sam Maiera6e76d72022-02-11 21:43:505616 changes = input_api.AffectedFiles(include_deletes=True,
5617 file_filter=FilterFile)
5618 potential_problems = []
5619 for f in changes:
5620 for line in f.GenerateScmDiff().splitlines():
5621 # Check deleted lines for pref registrations.
5622 if (line.startswith('-') and not line.startswith('--')
5623 and register_pref_pattern.search(line)):
5624 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105625
Sam Maiera6e76d72022-02-11 21:43:505626 if browser_prefs_file_pattern.search(f.LocalPath()):
5627 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5628 # assume that they knew that they have to deprecate preferences and don't
5629 # warn.
5630 try:
5631 if ModifiedPrefMigration(f):
5632 return []
5633 except Exception as e:
5634 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105635
Sam Maiera6e76d72022-02-11 21:43:505636 if potential_problems:
5637 return [
5638 output_api.PresubmitPromptWarning(
5639 'Discovered possible removal of preference registrations.\n\n'
5640 'Please make sure to properly deprecate preferences by clearing their\n'
5641 'value for a couple of milestones before finally removing the code.\n'
5642 'Otherwise data may stay in the preferences files forever. See\n'
5643 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5644 'chrome/browser/prefs/README.md for examples.\n'
5645 'This may be a false positive warning (e.g. if you move preference\n'
5646 'registrations to a different place).\n', potential_problems)
5647 ]
5648 return []
5649
Matt Stark6ef08872021-07-29 01:21:465650
5651def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505652 """Changes to GRD files must be consistent for tools to read them."""
5653 changed_grds = input_api.AffectedFiles(
5654 include_deletes=False,
5655 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5656 errors = []
5657 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5658 for matcher, msg in _INVALID_GRD_FILE_LINE]
5659 for grd in changed_grds:
5660 for i, line in enumerate(grd.NewContents()):
5661 for matcher, msg in invalid_file_regexes:
5662 if matcher.search(line):
5663 errors.append(
5664 output_api.PresubmitError(
5665 'Problem on {grd}:{i} - {msg}'.format(
5666 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5667 return errors
5668
Kevin McNee967dd2d22021-11-15 16:09:295669
5670def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505671 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5672 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5673 """
Kevin McNee967dd2d22021-11-15 16:09:295674
Ian Vollickdba956c2022-04-20 23:53:455675 # Only consider top-level directories that (1) can use content APIs or
5676 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5677 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505678 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455679 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295680 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455681 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505682 _HEADER_EXTENSIONS,
5683 )
5684 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5685 input_api.DEFAULT_FILES_TO_SKIP)
5686 source_file_filter = lambda f: input_api.FilterSourceFile(
5687 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295688
Sam Maiera6e76d72022-02-11 21:43:505689 # Note that since these are are just regular expressions and we don't have
5690 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5691 # could have a method named IsInMainFrame).
5692 concerning_class_pattern = input_api.re.compile(
5693 r'WebContentsObserver|WebContentsUserData')
5694 # A subset of WebContentsObserver overrides where there's particular risk for
5695 # confusing tab and page level operations and data (e.g. incorrectly
5696 # resetting page state in DidFinishNavigation).
5697 concerning_wco_methods = [
5698 'DidStartNavigation',
5699 'ReadyToCommitNavigation',
5700 'DidFinishNavigation',
5701 'RenderViewReady',
5702 'RenderViewDeleted',
5703 'RenderViewHostChanged',
5704 'PrimaryMainDocumentElementAvailable',
5705 'DocumentOnLoadCompletedInPrimaryMainFrame',
5706 'DOMContentLoaded',
5707 'DidFinishLoad',
5708 ]
5709 concerning_nav_handle_methods = [
5710 'IsInMainFrame',
5711 ]
5712 concerning_web_contents_methods = [
5713 'ForEachFrame',
5714 'GetAllFrames',
5715 'FromRenderFrameHost',
5716 'FromRenderViewHost',
5717 'GetMainFrame',
5718 'GetRenderViewHost',
5719 ]
5720 concerning_rfh_methods = [
5721 'GetParent',
5722 'GetMainFrame',
5723 'GetFrameTreeNodeId',
5724 ]
Ian Vollickc825b1f2022-04-19 14:30:155725 concerning_rfhi_methods = [
5726 'is_main_frame',
5727 ]
Ian Vollicka77a73ea2022-04-06 18:08:015728 concerning_ftn_methods = [
5729 'IsMainFrame',
5730 ]
Ian Vollickdba956c2022-04-20 23:53:455731 concerning_blink_frame_methods = [
5732 'IsCrossOriginToMainFrame',
5733 ]
Sam Maiera6e76d72022-02-11 21:43:505734 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5735 item for sublist in [
5736 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015737 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155738 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455739 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505740 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295741
Kevin McNee4eeec792022-02-14 20:02:045742 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505743 for f in input_api.AffectedFiles(include_deletes=False,
5744 file_filter=source_file_filter):
5745 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045746 class_match = concerning_class_pattern.search(line)
5747 if class_match:
5748 used_apis.add(class_match[0])
5749 method_match = concerning_method_pattern.search(line)
5750 if method_match:
5751 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505752
Kevin McNee4eeec792022-02-14 20:02:045753 if not used_apis:
5754 return []
Kevin McNee967dd2d22021-11-15 16:09:295755
Kevin McNee4eeec792022-02-14 20:02:045756 output_api.AppendCC('[email protected]')
5757 message = ('This change uses API(s) that are ambiguous in the presence of '
5758 'MPArch features such as bfcache, prerendering, and fenced '
5759 'frames.')
5760 explaination = (
5761 'Please double check whether new code assumes that a WebContents only '
5762 'contains a single page at a time. For example, it is discouraged to '
5763 'reset per-document state in response to the observation of a '
5764 'navigation. See this doc [1] and the comments on the individual APIs '
5765 'for guidance and this doc [2] for context. The MPArch review '
5766 'watchlist has been CC\'d on this change to help identify any issues.\n'
5767 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5768 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5769 )
5770 return [
5771 output_api.PresubmitNotifyResult(message,
5772 items=list(used_apis),
5773 long_text=explaination)
5774 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365775
5776
5777def CheckAssertAshOnlyCode(input_api, output_api):
5778 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5779 assert(is_chromeos_ash).
5780 """
5781
5782 def FileFilter(affected_file):
5783 """Includes directories known to be Ash only."""
5784 return input_api.FilterSourceFile(
5785 affected_file,
5786 files_to_check=(
5787 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5788 r'.*/ash/.*BUILD\.gn'), # Any path component.
5789 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5790
5791 errors = []
5792 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565793 for f in input_api.AffectedFiles(include_deletes=False,
5794 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365795 if (not pattern.search(input_api.ReadFile(f))):
5796 errors.append(
5797 output_api.PresubmitError(
5798 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5799 'possible, please create and issue and add a comment such '
5800 'as:\n # TODO(https://crbug.com/XXX): add '
5801 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5802 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275803
5804
5805def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505806 path = affected_file.LocalPath()
5807 if not _IsCPlusPlusFile(input_api, path):
5808 return False
5809
5810 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5811 if "/renderer/" in path:
5812 return True
5813
5814 # Blink's public/web API is only used/included by Renderer-only code. Note
5815 # that public/platform API may be used in non-Renderer processes (e.g. there
5816 # are some includes in code used by Utility, PDF, or Plugin processes).
5817 if "/blink/public/web/" in path:
5818 return True
5819
5820 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275821 return False
5822
Lukasz Anforowicz7016d05e2021-11-30 03:56:275823# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5824# by the Chromium Clang Plugin (which will be preferable because it will
5825# 1) report errors earlier - at compile-time and 2) cover more rules).
5826def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505827 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5828 errors = []
5829 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5830 # C++ comment.
5831 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5832 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5833 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5834 if raw_ptr_matcher.search(line):
5835 errors.append(
5836 output_api.PresubmitError(
5837 'Problem on {path}:{line} - '\
5838 'raw_ptr<T> should not be used in Renderer-only code '\
5839 '(as documented in the "Pointers to unprotected memory" '\
5840 'section in //base/memory/raw_ptr.md)'.format(
5841 path=f.LocalPath(), line=line_num)))
5842 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565843
5844
5845def CheckPythonShebang(input_api, output_api):
5846 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5847 system-wide python.
5848 """
5849 errors = []
5850 sources = lambda affected_file: input_api.FilterSourceFile(
5851 affected_file,
5852 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5853 r'third_party/blink/web_tests/external/') + input_api.
5854 DEFAULT_FILES_TO_SKIP),
5855 files_to_check=[r'.*\.py$'])
5856 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275857 for line_num, line in f.ChangedContents():
5858 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5859 errors.append(f.LocalPath())
5860 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565861
5862 result = []
5863 for file in errors:
5864 result.append(
5865 output_api.PresubmitError(
5866 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5867 file))
5868 return result