blob: a5d0502df278dd56a08aeb18315a8b4ba5e532f7 [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
Bruce Dawson4c4c2922022-05-02 18:07:331749 if f.LocalPath().endswith('com_imported_mstscax.h'):
1750 continue
Sam Maiera6e76d72022-02-11 21:43:501751 contents = input_api.ReadFile(f)
1752 if pattern.search(contents):
1753 files.append(f)
[email protected]6c063c62012-07-11 19:11:061754
Sam Maiera6e76d72022-02-11 21:43:501755 if files:
1756 return [
1757 output_api.PresubmitError(
1758 'Do not use #pragma once in header files.\n'
1759 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1760 files)
1761 ]
1762 return []
[email protected]6c063c62012-07-11 19:11:061763
[email protected]127f18ec2012-06-16 05:05:591764
Saagar Sanghavifceeaae2020-08-12 16:40:361765def CheckNoTrinaryTrueFalse(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501766 """Checks to make sure we don't introduce use of foo ? true : false."""
1767 problems = []
1768 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1769 for f in input_api.AffectedFiles():
1770 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1771 continue
[email protected]e7479052012-09-19 00:26:121772
Sam Maiera6e76d72022-02-11 21:43:501773 for line_num, line in f.ChangedContents():
1774 if pattern.match(line):
1775 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]e7479052012-09-19 00:26:121776
Sam Maiera6e76d72022-02-11 21:43:501777 if not problems:
1778 return []
1779 return [
1780 output_api.PresubmitPromptWarning(
1781 'Please consider avoiding the "? true : false" pattern if possible.\n'
1782 + '\n'.join(problems))
1783 ]
[email protected]e7479052012-09-19 00:26:121784
1785
Saagar Sanghavifceeaae2020-08-12 16:40:361786def CheckUnwantedDependencies(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501787 """Runs checkdeps on #include and import statements added in this
1788 change. Breaking - rules is an error, breaking ! rules is a
1789 warning.
1790 """
1791 # Return early if no relevant file types were modified.
1792 for f in input_api.AffectedFiles():
1793 path = f.LocalPath()
1794 if (_IsCPlusPlusFile(input_api, path) or _IsProtoFile(input_api, path)
1795 or _IsJavaFile(input_api, path)):
1796 break
[email protected]55f9f382012-07-31 11:02:181797 else:
Sam Maiera6e76d72022-02-11 21:43:501798 return []
rhalavati08acd232017-04-03 07:23:281799
Sam Maiera6e76d72022-02-11 21:43:501800 import sys
1801 # We need to wait until we have an input_api object and use this
1802 # roundabout construct to import checkdeps because this file is
1803 # eval-ed and thus doesn't have __file__.
1804 original_sys_path = sys.path
1805 try:
1806 sys.path = sys.path + [
1807 input_api.os_path.join(input_api.PresubmitLocalPath(),
1808 'buildtools', 'checkdeps')
1809 ]
1810 import checkdeps
1811 from rules import Rule
1812 finally:
1813 # Restore sys.path to what it was before.
1814 sys.path = original_sys_path
[email protected]55f9f382012-07-31 11:02:181815
Sam Maiera6e76d72022-02-11 21:43:501816 added_includes = []
1817 added_imports = []
1818 added_java_imports = []
1819 for f in input_api.AffectedFiles():
1820 if _IsCPlusPlusFile(input_api, f.LocalPath()):
1821 changed_lines = [line for _, line in f.ChangedContents()]
1822 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
1823 elif _IsProtoFile(input_api, f.LocalPath()):
1824 changed_lines = [line for _, line in f.ChangedContents()]
1825 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
1826 elif _IsJavaFile(input_api, f.LocalPath()):
1827 changed_lines = [line for _, line in f.ChangedContents()]
1828 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241829
Sam Maiera6e76d72022-02-11 21:43:501830 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
1831
1832 error_descriptions = []
1833 warning_descriptions = []
1834 error_subjects = set()
1835 warning_subjects = set()
1836
1837 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1838 added_includes):
1839 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1840 description_with_path = '%s\n %s' % (path, rule_description)
1841 if rule_type == Rule.DISALLOW:
1842 error_descriptions.append(description_with_path)
1843 error_subjects.add("#includes")
1844 else:
1845 warning_descriptions.append(description_with_path)
1846 warning_subjects.add("#includes")
1847
1848 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1849 added_imports):
1850 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1851 description_with_path = '%s\n %s' % (path, rule_description)
1852 if rule_type == Rule.DISALLOW:
1853 error_descriptions.append(description_with_path)
1854 error_subjects.add("imports")
1855 else:
1856 warning_descriptions.append(description_with_path)
1857 warning_subjects.add("imports")
1858
1859 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
1860 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
1861 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
1862 description_with_path = '%s\n %s' % (path, rule_description)
1863 if rule_type == Rule.DISALLOW:
1864 error_descriptions.append(description_with_path)
1865 error_subjects.add("imports")
1866 else:
1867 warning_descriptions.append(description_with_path)
1868 warning_subjects.add("imports")
1869
1870 results = []
1871 if error_descriptions:
1872 results.append(
1873 output_api.PresubmitError(
1874 'You added one or more %s that violate checkdeps rules.' %
1875 " and ".join(error_subjects), error_descriptions))
1876 if warning_descriptions:
1877 results.append(
1878 output_api.PresubmitPromptOrNotify(
1879 'You added one or more %s of files that are temporarily\n'
1880 'allowed but being removed. Can you avoid introducing the\n'
1881 '%s? See relevant DEPS file(s) for details and contacts.' %
1882 (" and ".join(warning_subjects), "/".join(warning_subjects)),
1883 warning_descriptions))
1884 return results
[email protected]55f9f382012-07-31 11:02:181885
1886
Saagar Sanghavifceeaae2020-08-12 16:40:361887def CheckFilePermissions(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501888 """Check that all files have their permissions properly set."""
1889 if input_api.platform == 'win32':
1890 return []
1891 checkperms_tool = input_api.os_path.join(input_api.PresubmitLocalPath(),
1892 'tools', 'checkperms',
1893 'checkperms.py')
1894 args = [
1895 input_api.python_executable, checkperms_tool, '--root',
1896 input_api.change.RepositoryRoot()
1897 ]
1898 with input_api.CreateTemporaryFile() as file_list:
1899 for f in input_api.AffectedFiles():
1900 # checkperms.py file/directory arguments must be relative to the
1901 # repository.
1902 file_list.write((f.LocalPath() + '\n').encode('utf8'))
1903 file_list.close()
1904 args += ['--file-list', file_list.name]
1905 try:
1906 input_api.subprocess.check_output(args)
1907 return []
1908 except input_api.subprocess.CalledProcessError as error:
1909 return [
1910 output_api.PresubmitError('checkperms.py failed:',
1911 long_text=error.output.decode(
1912 'utf-8', 'ignore'))
1913 ]
[email protected]fbcafe5a2012-08-08 15:31:221914
1915
Saagar Sanghavifceeaae2020-08-12 16:40:361916def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501917 """Makes sure we don't include ui/aura/window_property.h
1918 in header files.
1919 """
1920 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1921 errors = []
1922 for f in input_api.AffectedFiles():
1923 if not f.LocalPath().endswith('.h'):
1924 continue
1925 for line_num, line in f.ChangedContents():
1926 if pattern.match(line):
1927 errors.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]c8278b32012-10-30 20:35:491928
Sam Maiera6e76d72022-02-11 21:43:501929 results = []
1930 if errors:
1931 results.append(
1932 output_api.PresubmitError(
1933 'Header files should not include ui/aura/window_property.h',
1934 errors))
1935 return results
[email protected]c8278b32012-10-30 20:35:491936
1937
Omer Katzcc77ea92021-04-26 10:23:281938def CheckNoInternalHeapIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501939 """Makes sure we don't include any headers from
1940 third_party/blink/renderer/platform/heap/impl or
1941 third_party/blink/renderer/platform/heap/v8_wrapper from files outside of
1942 third_party/blink/renderer/platform/heap
1943 """
1944 impl_pattern = input_api.re.compile(
1945 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/impl/.*"')
1946 v8_wrapper_pattern = input_api.re.compile(
1947 r'^\s*#include\s*"third_party/blink/renderer/platform/heap/v8_wrapper/.*"'
1948 )
1949 file_filter = lambda f: not input_api.re.match(
1950 r"^third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]heap[\\/].*",
1951 f.LocalPath())
1952 errors = []
Omer Katzcc77ea92021-04-26 10:23:281953
Sam Maiera6e76d72022-02-11 21:43:501954 for f in input_api.AffectedFiles(file_filter=file_filter):
1955 for line_num, line in f.ChangedContents():
1956 if impl_pattern.match(line) or v8_wrapper_pattern.match(line):
1957 errors.append(' %s:%d' % (f.LocalPath(), line_num))
Omer Katzcc77ea92021-04-26 10:23:281958
Sam Maiera6e76d72022-02-11 21:43:501959 results = []
1960 if errors:
1961 results.append(
1962 output_api.PresubmitError(
1963 'Do not include files from third_party/blink/renderer/platform/heap/impl'
1964 ' or third_party/blink/renderer/platform/heap/v8_wrapper. Use the '
1965 'relevant counterparts from third_party/blink/renderer/platform/heap',
1966 errors))
1967 return results
Omer Katzcc77ea92021-04-26 10:23:281968
1969
[email protected]70ca77752012-11-20 03:45:031970def _CheckForVersionControlConflictsInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:501971 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1972 errors = []
1973 for line_num, line in f.ChangedContents():
1974 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
1975 # First-level headers in markdown look a lot like version control
1976 # conflict markers. http://daringfireball.net/projects/markdown/basics
1977 continue
1978 if pattern.match(line):
1979 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1980 return errors
[email protected]70ca77752012-11-20 03:45:031981
1982
Saagar Sanghavifceeaae2020-08-12 16:40:361983def CheckForVersionControlConflicts(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501984 """Usually this is not intentional and will cause a compile failure."""
1985 errors = []
1986 for f in input_api.AffectedFiles():
1987 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
[email protected]70ca77752012-11-20 03:45:031988
Sam Maiera6e76d72022-02-11 21:43:501989 results = []
1990 if errors:
1991 results.append(
1992 output_api.PresubmitError(
1993 'Version control conflict markers found, please resolve.',
1994 errors))
1995 return results
[email protected]70ca77752012-11-20 03:45:031996
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201997
Saagar Sanghavifceeaae2020-08-12 16:40:361998def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:501999 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2000 errors = []
2001 for f in input_api.AffectedFiles():
2002 for line_num, line in f.ChangedContents():
2003 if pattern.search(line):
2004 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
estadee17314a02017-01-12 16:22:162005
Sam Maiera6e76d72022-02-11 21:43:502006 results = []
2007 if errors:
2008 results.append(
2009 output_api.PresubmitPromptWarning(
2010 'Found Google support URL addressed by answer number. Please replace '
2011 'with a p= identifier instead. See crbug.com/679462\n',
2012 errors))
2013 return results
estadee17314a02017-01-12 16:22:162014
[email protected]70ca77752012-11-20 03:45:032015
Saagar Sanghavifceeaae2020-08-12 16:40:362016def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502017 def FilterFile(affected_file):
2018 """Filter function for use with input_api.AffectedSourceFiles,
2019 below. This filters out everything except non-test files from
2020 top-level directories that generally speaking should not hard-code
2021 service URLs (e.g. src/android_webview/, src/content/ and others).
2022 """
2023 return input_api.FilterSourceFile(
2024 affected_file,
2025 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2026 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2027 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442028
Sam Maiera6e76d72022-02-11 21:43:502029 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2030 '\.(com|net)[^"]*"')
2031 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2032 pattern = input_api.re.compile(base_pattern)
2033 problems = [] # items are (filename, line_number, line)
2034 for f in input_api.AffectedSourceFiles(FilterFile):
2035 for line_num, line in f.ChangedContents():
2036 if not comment_pattern.search(line) and pattern.search(line):
2037 problems.append((f.LocalPath(), line_num, line))
[email protected]06e6d0ff2012-12-11 01:36:442038
Sam Maiera6e76d72022-02-11 21:43:502039 if problems:
2040 return [
2041 output_api.PresubmitPromptOrNotify(
2042 'Most layers below src/chrome/ should not hardcode service URLs.\n'
2043 'Are you sure this is correct?', [
2044 ' %s:%d: %s' % (problem[0], problem[1], problem[2])
2045 for problem in problems
2046 ])
2047 ]
2048 else:
2049 return []
[email protected]06e6d0ff2012-12-11 01:36:442050
2051
Saagar Sanghavifceeaae2020-08-12 16:40:362052def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502053 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
James Cook6b6597c2019-11-06 22:05:292054
Sam Maiera6e76d72022-02-11 21:43:502055 def FileFilter(affected_file):
2056 """Includes directories known to be Chrome OS only."""
2057 return input_api.FilterSourceFile(
2058 affected_file,
2059 files_to_check=(
2060 '^ash/',
2061 '^chromeos/', # Top-level src/chromeos.
2062 '.*/chromeos/', # Any path component.
2063 '^components/arc',
2064 '^components/exo'),
2065 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292066
Sam Maiera6e76d72022-02-11 21:43:502067 prefs = []
2068 priority_prefs = []
2069 for f in input_api.AffectedFiles(file_filter=FileFilter):
2070 for line_num, line in f.ChangedContents():
2071 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF',
2072 line):
2073 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2074 prefs.append(' %s' % line)
2075 if input_api.re.search(
2076 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2077 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2078 priority_prefs.append(' %s' % line)
2079
2080 results = []
2081 if (prefs):
2082 results.append(
2083 output_api.PresubmitPromptWarning(
2084 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2085 'by browser sync settings. If these prefs should be controlled by OS '
2086 'sync settings use SYNCABLE_OS_PREF instead.\n' +
2087 '\n'.join(prefs)))
2088 if (priority_prefs):
2089 results.append(
2090 output_api.PresubmitPromptWarning(
2091 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2092 'controlled by browser sync settings. If these prefs should be '
2093 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2094 'instead.\n' + '\n'.join(prefs)))
2095 return results
James Cook6b6597c2019-11-06 22:05:292096
2097
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492098# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362099def CheckNoAbbreviationInPngFileName(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502100 """Makes sure there are no abbreviations in the name of PNG files.
2101 The native_client_sdk directory is excluded because it has auto-generated PNG
2102 files for documentation.
2103 """
2104 errors = []
2105 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Bruce Dawson3db456212022-05-02 05:34:182106 files_to_skip = [r'^native_client_sdk[\\/]',
2107 r'^services[\\/]test[\\/]',
2108 r'^third_party[\\/]blink[\\/]web_tests[\\/]',
2109 ]
Sam Maiera6e76d72022-02-11 21:43:502110 file_filter = lambda f: input_api.FilterSourceFile(
2111 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
2112 for f in input_api.AffectedFiles(include_deletes=False,
2113 file_filter=file_filter):
2114 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272115
Sam Maiera6e76d72022-02-11 21:43:502116 results = []
2117 if errors:
2118 results.append(
2119 output_api.PresubmitError(
2120 'The name of PNG files should not have abbreviations. \n'
2121 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2122 'Contact [email protected] if you have questions.', errors))
2123 return results
[email protected]d2530012013-01-25 16:39:272124
2125
Daniel Cheng4dcdb6b2017-04-13 08:30:172126def _ExtractAddRulesFromParsedDeps(parsed_deps):
Sam Maiera6e76d72022-02-11 21:43:502127 """Extract the rules that add dependencies from a parsed DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172128
Sam Maiera6e76d72022-02-11 21:43:502129 Args:
2130 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2131 add_rules = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172132 add_rules.update([
Sam Maiera6e76d72022-02-11 21:43:502133 rule[1:] for rule in parsed_deps.get('include_rules', [])
Daniel Cheng4dcdb6b2017-04-13 08:30:172134 if rule.startswith('+') or rule.startswith('!')
2135 ])
Sam Maiera6e76d72022-02-11 21:43:502136 for _, rules in parsed_deps.get('specific_include_rules', {}).items():
2137 add_rules.update([
2138 rule[1:] for rule in rules
2139 if rule.startswith('+') or rule.startswith('!')
2140 ])
2141 return add_rules
Daniel Cheng4dcdb6b2017-04-13 08:30:172142
2143
2144def _ParseDeps(contents):
Sam Maiera6e76d72022-02-11 21:43:502145 """Simple helper for parsing DEPS files."""
Daniel Cheng4dcdb6b2017-04-13 08:30:172146
Sam Maiera6e76d72022-02-11 21:43:502147 # Stubs for handling special syntax in the root DEPS file.
2148 class _VarImpl:
2149 def __init__(self, local_scope):
2150 self._local_scope = local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172151
Sam Maiera6e76d72022-02-11 21:43:502152 def Lookup(self, var_name):
2153 """Implements the Var syntax."""
2154 try:
2155 return self._local_scope['vars'][var_name]
2156 except KeyError:
2157 raise Exception('Var is not defined: %s' % var_name)
Daniel Cheng4dcdb6b2017-04-13 08:30:172158
Sam Maiera6e76d72022-02-11 21:43:502159 local_scope = {}
2160 global_scope = {
2161 'Var': _VarImpl(local_scope).Lookup,
2162 'Str': str,
2163 }
Dirk Pranke1b9e06382021-05-14 01:16:222164
Sam Maiera6e76d72022-02-11 21:43:502165 exec(contents, global_scope, local_scope)
2166 return local_scope
Daniel Cheng4dcdb6b2017-04-13 08:30:172167
2168
2169def _CalculateAddedDeps(os_path, old_contents, new_contents):
Sam Maiera6e76d72022-02-11 21:43:502170 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
2171 a set of DEPS entries that we should look up.
[email protected]14a6131c2014-01-08 01:15:412172
Sam Maiera6e76d72022-02-11 21:43:502173 For a directory (rather than a specific filename) we fake a path to
2174 a specific filename by adding /DEPS. This is chosen as a file that
2175 will seldom or never be subject to per-file include_rules.
2176 """
2177 # We ignore deps entries on auto-generated directories.
2178 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082179
Sam Maiera6e76d72022-02-11 21:43:502180 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2181 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
Daniel Cheng4dcdb6b2017-04-13 08:30:172182
Sam Maiera6e76d72022-02-11 21:43:502183 added_deps = new_deps.difference(old_deps)
Daniel Cheng4dcdb6b2017-04-13 08:30:172184
Sam Maiera6e76d72022-02-11 21:43:502185 results = set()
2186 for added_dep in added_deps:
2187 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2188 continue
2189 # Assume that a rule that ends in .h is a rule for a specific file.
2190 if added_dep.endswith('.h'):
2191 results.add(added_dep)
2192 else:
2193 results.add(os_path.join(added_dep, 'DEPS'))
2194 return results
[email protected]f32e2d1e2013-07-26 21:39:082195
2196
Saagar Sanghavifceeaae2020-08-12 16:40:362197def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502198 """When a dependency prefixed with + is added to a DEPS file, we
2199 want to make sure that the change is reviewed by an OWNER of the
2200 target file or directory, to avoid layering violations from being
2201 introduced. This check verifies that this happens.
2202 """
2203 # We rely on Gerrit's code-owners to check approvals.
2204 # input_api.gerrit is always set for Chromium, but other projects
2205 # might not use Gerrit.
2206 if not input_api.gerrit:
2207 return []
2208 if (input_api.change.issue and input_api.gerrit.IsOwnersOverrideApproved(
2209 input_api.change.issue)):
2210 # Skip OWNERS check when Owners-Override label is approved. This is intended
2211 # for global owners, trusted bots, and on-call sheriffs. Review is still
2212 # required for these changes.
2213 return []
Edward Lesmes6fba51082021-01-20 04:20:232214
Sam Maiera6e76d72022-02-11 21:43:502215 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242216
Sam Maiera6e76d72022-02-11 21:43:502217 file_filter = lambda f: not input_api.re.match(
2218 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
2219 for f in input_api.AffectedFiles(include_deletes=False,
2220 file_filter=file_filter):
2221 filename = input_api.os_path.basename(f.LocalPath())
2222 if filename == 'DEPS':
2223 virtual_depended_on_files.update(
2224 _CalculateAddedDeps(input_api.os_path,
2225 '\n'.join(f.OldContents()),
2226 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552227
Sam Maiera6e76d72022-02-11 21:43:502228 if not virtual_depended_on_files:
2229 return []
[email protected]e871964c2013-05-13 14:14:552230
Sam Maiera6e76d72022-02-11 21:43:502231 if input_api.is_committing:
2232 if input_api.tbr:
2233 return [
2234 output_api.PresubmitNotifyResult(
2235 '--tbr was specified, skipping OWNERS check for DEPS additions'
2236 )
2237 ]
2238 if input_api.dry_run:
2239 return [
2240 output_api.PresubmitNotifyResult(
2241 'This is a dry run, skipping OWNERS check for DEPS additions'
2242 )
2243 ]
2244 if not input_api.change.issue:
2245 return [
2246 output_api.PresubmitError(
2247 "DEPS approval by OWNERS check failed: this change has "
2248 "no change number, so we can't check it for approvals.")
2249 ]
2250 output = output_api.PresubmitError
[email protected]14a6131c2014-01-08 01:15:412251 else:
Sam Maiera6e76d72022-02-11 21:43:502252 output = output_api.PresubmitNotifyResult
[email protected]e871964c2013-05-13 14:14:552253
Sam Maiera6e76d72022-02-11 21:43:502254 owner_email, reviewers = (
2255 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2256 input_api, None, approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552257
Sam Maiera6e76d72022-02-11 21:43:502258 owner_email = owner_email or input_api.change.author_email
2259
2260 approval_status = input_api.owners_client.GetFilesApprovalStatus(
2261 virtual_depended_on_files, reviewers.union([owner_email]), [])
2262 missing_files = [
2263 f for f in virtual_depended_on_files
2264 if approval_status[f] != input_api.owners_client.APPROVED
2265 ]
2266
2267 # We strip the /DEPS part that was added by
2268 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2269 # directory.
2270 def StripDeps(path):
2271 start_deps = path.rfind('/DEPS')
2272 if start_deps != -1:
2273 return path[:start_deps]
2274 else:
2275 return path
2276
2277 unapproved_dependencies = [
2278 "'+%s'," % StripDeps(path) for path in missing_files
2279 ]
2280
2281 if unapproved_dependencies:
2282 output_list = [
2283 output(
2284 'You need LGTM from owners of depends-on paths in DEPS that were '
2285 'modified in this CL:\n %s' %
2286 '\n '.join(sorted(unapproved_dependencies)))
2287 ]
2288 suggested_owners = input_api.owners_client.SuggestOwners(
2289 missing_files, exclude=[owner_email])
2290 output_list.append(
2291 output('Suggested missing target path OWNERS:\n %s' %
2292 '\n '.join(suggested_owners or [])))
2293 return output_list
2294
2295 return []
[email protected]e871964c2013-05-13 14:14:552296
2297
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492298# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362299def CheckSpamLogging(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502300 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2301 files_to_skip = (
2302 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2303 input_api.DEFAULT_FILES_TO_SKIP + (
2304 r"^base[\\/]logging\.h$",
2305 r"^base[\\/]logging\.cc$",
2306 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2307 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2308 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2309 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2310 r"startup_browser_creator\.cc$",
2311 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2312 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2313 r"diagnostics_writer\.cc$",
2314 r"^chrome[\\/]chrome_cleaner[\\/].*",
2315 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2316 r"dll_hash_main\.cc$",
2317 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2318 r"^chromecast[\\/]",
Sam Maiera6e76d72022-02-11 21:43:502319 r"^components[\\/]browser_watcher[\\/]"
2320 r"dump_stability_report_main_win.cc$",
2321 r"^components[\\/]media_control[\\/]renderer[\\/]"
2322 r"media_playback_options\.cc$",
2323 r"^components[\\/]viz[\\/]service[\\/]display[\\/]"
2324 r"overlay_strategy_underlay_cast\.cc$",
2325 r"^components[\\/]zucchini[\\/].*",
2326 # TODO(peter): Remove exception. https://crbug.com/534537
2327 r"^content[\\/]browser[\\/]notifications[\\/]"
2328 r"notification_event_dispatcher_impl\.cc$",
2329 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2330 r"gl_helper_benchmark\.cc$",
2331 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2332 r"^courgette[\\/]courgette_tool\.cc$",
2333 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2334 r"^fuchsia[\\/]base[\\/]init_logging.cc$",
2335 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2336 r"^fuchsia[\\/]runners[\\/]common[\\/]web_component.cc$",
2337 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2338 r"^ipc[\\/]ipc_logging\.cc$",
2339 r"^native_client_sdk[\\/]",
2340 r"^remoting[\\/]base[\\/]logging\.h$",
2341 r"^remoting[\\/]host[\\/].*",
2342 r"^sandbox[\\/]linux[\\/].*",
2343 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2344 r"dump_file_system.cc$",
2345 r"^tools[\\/]",
2346 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2347 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2348 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2349 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2350 r"xwmstartupcheck\.cc$"))
2351 source_file_filter = lambda x: input_api.FilterSourceFile(
2352 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402353
Sam Maiera6e76d72022-02-11 21:43:502354 log_info = set([])
2355 printf = set([])
[email protected]85218562013-11-22 07:41:402356
Sam Maiera6e76d72022-02-11 21:43:502357 for f in input_api.AffectedSourceFiles(source_file_filter):
2358 for _, line in f.ChangedContents():
2359 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2360 log_info.add(f.LocalPath())
2361 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2362 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372363
Sam Maiera6e76d72022-02-11 21:43:502364 if input_api.re.search(r"\bprintf\(", line):
2365 printf.add(f.LocalPath())
2366 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2367 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402368
Sam Maiera6e76d72022-02-11 21:43:502369 if log_info:
2370 return [
2371 output_api.PresubmitError(
2372 'These files spam the console log with LOG(INFO):',
2373 items=log_info)
2374 ]
2375 if printf:
2376 return [
2377 output_api.PresubmitError(
2378 'These files spam the console log with printf/fprintf:',
2379 items=printf)
2380 ]
2381 return []
[email protected]85218562013-11-22 07:41:402382
2383
Saagar Sanghavifceeaae2020-08-12 16:40:362384def CheckForAnonymousVariables(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502385 """These types are all expected to hold locks while in scope and
2386 so should never be anonymous (which causes them to be immediately
2387 destroyed)."""
2388 they_who_must_be_named = [
2389 'base::AutoLock',
2390 'base::AutoReset',
2391 'base::AutoUnlock',
2392 'SkAutoAlphaRestore',
2393 'SkAutoBitmapShaderInstall',
2394 'SkAutoBlitterChoose',
2395 'SkAutoBounderCommit',
2396 'SkAutoCallProc',
2397 'SkAutoCanvasRestore',
2398 'SkAutoCommentBlock',
2399 'SkAutoDescriptor',
2400 'SkAutoDisableDirectionCheck',
2401 'SkAutoDisableOvalCheck',
2402 'SkAutoFree',
2403 'SkAutoGlyphCache',
2404 'SkAutoHDC',
2405 'SkAutoLockColors',
2406 'SkAutoLockPixels',
2407 'SkAutoMalloc',
2408 'SkAutoMaskFreeImage',
2409 'SkAutoMutexAcquire',
2410 'SkAutoPathBoundsUpdate',
2411 'SkAutoPDFRelease',
2412 'SkAutoRasterClipValidate',
2413 'SkAutoRef',
2414 'SkAutoTime',
2415 'SkAutoTrace',
2416 'SkAutoUnref',
2417 ]
2418 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2419 # bad: base::AutoLock(lock.get());
2420 # not bad: base::AutoLock lock(lock.get());
2421 bad_pattern = input_api.re.compile(anonymous)
2422 # good: new base::AutoLock(lock.get())
2423 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2424 errors = []
[email protected]49aa76a2013-12-04 06:59:162425
Sam Maiera6e76d72022-02-11 21:43:502426 for f in input_api.AffectedFiles():
2427 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2428 continue
2429 for linenum, line in f.ChangedContents():
2430 if bad_pattern.search(line) and not good_pattern.search(line):
2431 errors.append('%s:%d' % (f.LocalPath(), linenum))
[email protected]49aa76a2013-12-04 06:59:162432
Sam Maiera6e76d72022-02-11 21:43:502433 if errors:
2434 return [
2435 output_api.PresubmitError(
2436 'These lines create anonymous variables that need to be named:',
2437 items=errors)
2438 ]
2439 return []
[email protected]49aa76a2013-12-04 06:59:162440
2441
Saagar Sanghavifceeaae2020-08-12 16:40:362442def CheckUniquePtrOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502443 # Returns whether |template_str| is of the form <T, U...> for some types T
2444 # and U. Assumes that |template_str| is already in the form <...>.
2445 def HasMoreThanOneArg(template_str):
2446 # Level of <...> nesting.
2447 nesting = 0
2448 for c in template_str:
2449 if c == '<':
2450 nesting += 1
2451 elif c == '>':
2452 nesting -= 1
2453 elif c == ',' and nesting == 1:
2454 return True
2455 return False
Vaclav Brozekb7fadb692018-08-30 06:39:532456
Sam Maiera6e76d72022-02-11 21:43:502457 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
2458 sources = lambda affected_file: input_api.FilterSourceFile(
2459 affected_file,
2460 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
2461 DEFAULT_FILES_TO_SKIP),
2462 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552463
Sam Maiera6e76d72022-02-11 21:43:502464 # Pattern to capture a single "<...>" block of template arguments. It can
2465 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2466 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2467 # latter would likely require counting that < and > match, which is not
2468 # expressible in regular languages. Should the need arise, one can introduce
2469 # limited counting (matching up to a total number of nesting depth), which
2470 # should cover all practical cases for already a low nesting limit.
2471 template_arg_pattern = (
2472 r'<[^>]*' # Opening block of <.
2473 r'>([^<]*>)?') # Closing block of >.
2474 # Prefix expressing that whatever follows is not already inside a <...>
2475 # block.
2476 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
2477 null_construct_pattern = input_api.re.compile(
2478 not_inside_template_arg_pattern + r'\bstd::unique_ptr' +
2479 template_arg_pattern + r'\(\)')
Vaclav Brozeka54c528b2018-04-06 19:23:552480
Sam Maiera6e76d72022-02-11 21:43:502481 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2482 template_arg_no_array_pattern = (
2483 r'<[^>]*[^]]' # Opening block of <.
2484 r'>([^(<]*[^]]>)?') # Closing block of >.
2485 # Prefix saying that what follows is the start of an expression.
2486 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2487 # Suffix saying that what follows are call parentheses with a non-empty list
2488 # of arguments.
2489 nonempty_arg_list_pattern = r'\(([^)]|$)'
2490 # Put the template argument into a capture group for deeper examination later.
2491 return_construct_pattern = input_api.re.compile(
2492 start_of_expr_pattern + r'std::unique_ptr' + '(?P<template_arg>' +
2493 template_arg_no_array_pattern + ')' + nonempty_arg_list_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552494
Sam Maiera6e76d72022-02-11 21:43:502495 problems_constructor = []
2496 problems_nullptr = []
2497 for f in input_api.AffectedSourceFiles(sources):
2498 for line_number, line in f.ChangedContents():
2499 # Disallow:
2500 # return std::unique_ptr<T>(foo);
2501 # bar = std::unique_ptr<T>(foo);
2502 # But allow:
2503 # return std::unique_ptr<T[]>(foo);
2504 # bar = std::unique_ptr<T[]>(foo);
2505 # And also allow cases when the second template argument is present. Those
2506 # cases cannot be handled by std::make_unique:
2507 # return std::unique_ptr<T, U>(foo);
2508 # bar = std::unique_ptr<T, U>(foo);
2509 local_path = f.LocalPath()
2510 return_construct_result = return_construct_pattern.search(line)
2511 if return_construct_result and not HasMoreThanOneArg(
2512 return_construct_result.group('template_arg')):
2513 problems_constructor.append(
2514 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2515 # Disallow:
2516 # std::unique_ptr<T>()
2517 if null_construct_pattern.search(line):
2518 problems_nullptr.append(
2519 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Vaclav Brozek851d9602018-04-04 16:13:052520
Sam Maiera6e76d72022-02-11 21:43:502521 errors = []
2522 if problems_nullptr:
2523 errors.append(
2524 output_api.PresubmitPromptWarning(
2525 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
2526 problems_nullptr))
2527 if problems_constructor:
2528 errors.append(
2529 output_api.PresubmitError(
2530 'The following files use explicit std::unique_ptr constructor. '
2531 'Use std::make_unique<T>() instead, or use base::WrapUnique if '
2532 'std::make_unique is not an option.', problems_constructor))
2533 return errors
Peter Kasting4844e46e2018-02-23 07:27:102534
2535
Saagar Sanghavifceeaae2020-08-12 16:40:362536def CheckUserActionUpdate(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:502537 """Checks if any new user action has been added."""
2538 if any('actions.xml' == input_api.os_path.basename(f)
2539 for f in input_api.LocalPaths()):
2540 # If actions.xml is already included in the changelist, the PRESUBMIT
2541 # for actions.xml will do a more complete presubmit check.
2542 return []
2543
2544 file_inclusion_pattern = [r'.*\.(cc|mm)$']
2545 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2546 input_api.DEFAULT_FILES_TO_SKIP)
2547 file_filter = lambda f: input_api.FilterSourceFile(
2548 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
2549
2550 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
2551 current_actions = None
2552 for f in input_api.AffectedFiles(file_filter=file_filter):
2553 for line_num, line in f.ChangedContents():
2554 match = input_api.re.search(action_re, line)
2555 if match:
2556 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2557 # loaded only once.
2558 if not current_actions:
2559 with open(
2560 'tools/metrics/actions/actions.xml') as actions_f:
2561 current_actions = actions_f.read()
2562 # Search for the matched user action name in |current_actions|.
2563 for action_name in match.groups():
2564 action = 'name="{0}"'.format(action_name)
2565 if action not in current_actions:
2566 return [
2567 output_api.PresubmitPromptWarning(
2568 'File %s line %d: %s is missing in '
2569 'tools/metrics/actions/actions.xml. Please run '
2570 'tools/metrics/actions/extract_actions.py to update.'
2571 % (f.LocalPath(), line_num, action_name))
2572 ]
[email protected]999261d2014-03-03 20:08:082573 return []
2574
[email protected]999261d2014-03-03 20:08:082575
Daniel Cheng13ca61a882017-08-25 15:11:252576def _ImportJSONCommentEater(input_api):
Sam Maiera6e76d72022-02-11 21:43:502577 import sys
2578 sys.path = sys.path + [
2579 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2580 'json_comment_eater')
2581 ]
2582 import json_comment_eater
2583 return json_comment_eater
Daniel Cheng13ca61a882017-08-25 15:11:252584
2585
[email protected]99171a92014-06-03 08:44:472586def _GetJSONParseError(input_api, filename, eat_comments=True):
dchenge07de812016-06-20 19:27:172587 try:
Sam Maiera6e76d72022-02-11 21:43:502588 contents = input_api.ReadFile(filename)
2589 if eat_comments:
2590 json_comment_eater = _ImportJSONCommentEater(input_api)
2591 contents = json_comment_eater.Nom(contents)
dchenge07de812016-06-20 19:27:172592
Sam Maiera6e76d72022-02-11 21:43:502593 input_api.json.loads(contents)
2594 except ValueError as e:
2595 return e
Andrew Grieve4deedb12022-02-03 21:34:502596 return None
2597
2598
Sam Maiera6e76d72022-02-11 21:43:502599def _GetIDLParseError(input_api, filename):
2600 try:
2601 contents = input_api.ReadFile(filename)
Devlin Croninf7582a12022-04-21 21:14:282602 for i, char in enumerate(contents):
2603 if not char.isascii():
2604 return ('Non-ascii character "%s" (ord %d) found at offset %d.'
2605 % (char, ord(char), i))
Sam Maiera6e76d72022-02-11 21:43:502606 idl_schema = input_api.os_path.join(input_api.PresubmitLocalPath(),
2607 'tools', 'json_schema_compiler',
2608 'idl_schema.py')
2609 process = input_api.subprocess.Popen(
Bruce Dawson679fb082022-04-14 00:47:282610 [input_api.python3_executable, idl_schema],
Sam Maiera6e76d72022-02-11 21:43:502611 stdin=input_api.subprocess.PIPE,
2612 stdout=input_api.subprocess.PIPE,
2613 stderr=input_api.subprocess.PIPE,
2614 universal_newlines=True)
2615 (_, error) = process.communicate(input=contents)
2616 return error or None
2617 except ValueError as e:
2618 return e
agrievef32bcc72016-04-04 14:57:402619
agrievef32bcc72016-04-04 14:57:402620
Sam Maiera6e76d72022-02-11 21:43:502621def CheckParseErrors(input_api, output_api):
2622 """Check that IDL and JSON files do not contain syntax errors."""
2623 actions = {
2624 '.idl': _GetIDLParseError,
2625 '.json': _GetJSONParseError,
2626 }
2627 # Most JSON files are preprocessed and support comments, but these do not.
2628 json_no_comments_patterns = [
2629 r'^testing[\\/]',
2630 ]
2631 # Only run IDL checker on files in these directories.
2632 idl_included_patterns = [
2633 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2634 r'^extensions[\\/]common[\\/]api[\\/]',
2635 ]
agrievef32bcc72016-04-04 14:57:402636
Sam Maiera6e76d72022-02-11 21:43:502637 def get_action(affected_file):
2638 filename = affected_file.LocalPath()
2639 return actions.get(input_api.os_path.splitext(filename)[1])
agrievef32bcc72016-04-04 14:57:402640
Sam Maiera6e76d72022-02-11 21:43:502641 def FilterFile(affected_file):
2642 action = get_action(affected_file)
2643 if not action:
2644 return False
2645 path = affected_file.LocalPath()
agrievef32bcc72016-04-04 14:57:402646
Sam Maiera6e76d72022-02-11 21:43:502647 if _MatchesFile(input_api,
2648 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS, path):
2649 return False
2650
2651 if (action == _GetIDLParseError
2652 and not _MatchesFile(input_api, idl_included_patterns, path)):
2653 return False
2654 return True
2655
2656 results = []
2657 for affected_file in input_api.AffectedFiles(file_filter=FilterFile,
2658 include_deletes=False):
2659 action = get_action(affected_file)
2660 kwargs = {}
2661 if (action == _GetJSONParseError
2662 and _MatchesFile(input_api, json_no_comments_patterns,
2663 affected_file.LocalPath())):
2664 kwargs['eat_comments'] = False
2665 parse_error = action(input_api, affected_file.AbsoluteLocalPath(),
2666 **kwargs)
2667 if parse_error:
2668 results.append(
2669 output_api.PresubmitError(
2670 '%s could not be parsed: %s' %
2671 (affected_file.LocalPath(), parse_error)))
2672 return results
2673
2674
2675def CheckJavaStyle(input_api, output_api):
2676 """Runs checkstyle on changed java files and returns errors if any exist."""
2677
2678 # Return early if no java files were modified.
2679 if not any(
2680 _IsJavaFile(input_api, f.LocalPath())
2681 for f in input_api.AffectedFiles()):
2682 return []
2683
2684 import sys
2685 original_sys_path = sys.path
2686 try:
2687 sys.path = sys.path + [
2688 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
2689 'android', 'checkstyle')
2690 ]
2691 import checkstyle
2692 finally:
2693 # Restore sys.path to what it was before.
2694 sys.path = original_sys_path
2695
2696 return checkstyle.RunCheckstyle(
2697 input_api,
2698 output_api,
2699 'tools/android/checkstyle/chromium-style-5.0.xml',
2700 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
2701
2702
2703def CheckPythonDevilInit(input_api, output_api):
2704 """Checks to make sure devil is initialized correctly in python scripts."""
2705 script_common_initialize_pattern = input_api.re.compile(
2706 r'script_common\.InitializeEnvironment\(')
2707 devil_env_config_initialize = input_api.re.compile(
2708 r'devil_env\.config\.Initialize\(')
2709
2710 errors = []
2711
2712 sources = lambda affected_file: input_api.FilterSourceFile(
2713 affected_file,
2714 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + (
2715 r'^build[\\/]android[\\/]devil_chromium\.py',
2716 r'^third_party[\\/].*',
2717 )),
2718 files_to_check=[r'.*\.py$'])
2719
2720 for f in input_api.AffectedSourceFiles(sources):
2721 for line_num, line in f.ChangedContents():
2722 if (script_common_initialize_pattern.search(line)
2723 or devil_env_config_initialize.search(line)):
2724 errors.append("%s:%d" % (f.LocalPath(), line_num))
2725
2726 results = []
2727
2728 if errors:
2729 results.append(
2730 output_api.PresubmitError(
2731 'Devil initialization should always be done using '
2732 'devil_chromium.Initialize() in the chromium project, to use better '
2733 'defaults for dependencies (ex. up-to-date version of adb).',
2734 errors))
2735
2736 return results
2737
2738
2739def _MatchesFile(input_api, patterns, path):
2740 for pattern in patterns:
2741 if input_api.re.search(pattern, path):
2742 return True
2743 return False
2744
2745
2746def _GetOwnersFilesToCheckForIpcOwners(input_api):
2747 """Gets a list of OWNERS files to check for correct security owners.
2748
2749 Returns:
2750 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2751 contain to cover IPC-related files with noparent reviewer rules.
2752 """
2753 # Whether or not a file affects IPC is (mostly) determined by a simple list
2754 # of filename patterns.
2755 file_patterns = [
2756 # Legacy IPC:
2757 '*_messages.cc',
2758 '*_messages*.h',
2759 '*_param_traits*.*',
2760 # Mojo IPC:
2761 '*.mojom',
2762 '*_mojom_traits*.*',
2763 '*_struct_traits*.*',
2764 '*_type_converter*.*',
2765 '*.typemap',
2766 # Android native IPC:
2767 '*.aidl',
2768 # Blink uses a different file naming convention:
2769 '*EnumTraits*.*',
2770 "*MojomTraits*.*",
2771 '*StructTraits*.*',
2772 '*TypeConverter*.*',
2773 ]
2774
2775 # These third_party directories do not contain IPCs, but contain files
2776 # matching the above patterns, which trigger false positives.
2777 exclude_paths = [
2778 'third_party/crashpad/*',
2779 'third_party/blink/renderer/platform/bindings/*',
2780 'third_party/protobuf/benchmarks/python/*',
2781 'third_party/win_build_output/*',
2782 # These files are just used to communicate between class loaders running
2783 # in the same process.
2784 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
2785 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2786 ]
2787
2788 # Dictionary mapping an OWNERS file path to Patterns.
2789 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2790 # rules ) to a PatternEntry.
2791 # PatternEntry is a dictionary with two keys:
2792 # - 'files': the files that are matched by this pattern
2793 # - 'rules': the per-file rules needed for this pattern
2794 # For example, if we expect OWNERS file to contain rules for *.mojom and
2795 # *_struct_traits*.*, Patterns might look like this:
2796 # {
2797 # '*.mojom': {
2798 # 'files': ...,
2799 # 'rules': [
2800 # 'per-file *.mojom=set noparent',
2801 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2802 # ],
2803 # },
2804 # '*_struct_traits*.*': {
2805 # 'files': ...,
2806 # 'rules': [
2807 # 'per-file *_struct_traits*.*=set noparent',
2808 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2809 # ],
2810 # },
2811 # }
2812 to_check = {}
2813
2814 def AddPatternToCheck(input_file, pattern):
2815 owners_file = input_api.os_path.join(
2816 input_api.os_path.dirname(input_file.AbsoluteLocalPath()),
2817 'OWNERS')
2818 if owners_file not in to_check:
2819 to_check[owners_file] = {}
2820 if pattern not in to_check[owners_file]:
2821 to_check[owners_file][pattern] = {
2822 'files': [],
2823 'rules': [
2824 'per-file %s=set noparent' % pattern,
2825 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2826 ]
2827 }
2828 to_check[owners_file][pattern]['files'].append(input_file)
2829
2830 # Iterate through the affected files to see what we actually need to check
2831 # for. We should only nag patch authors about per-file rules if a file in that
2832 # directory would match that pattern. If a directory only contains *.mojom
2833 # files and no *_messages*.h files, we should only nag about rules for
2834 # *.mojom files.
2835 for f in input_api.AffectedFiles(include_deletes=False):
2836 # Manifest files don't have a strong naming convention. Instead, try to find
2837 # affected .cc and .h files which look like they contain a manifest
2838 # definition.
2839 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2840 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2841 if (manifest_pattern.search(f.LocalPath())
2842 and not test_manifest_pattern.search(f.LocalPath())):
2843 # We expect all actual service manifest files to contain at least one
2844 # qualified reference to service_manager::Manifest.
2845 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2846 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
2847 for pattern in file_patterns:
2848 if input_api.fnmatch.fnmatch(
2849 input_api.os_path.basename(f.LocalPath()), pattern):
2850 skip = False
2851 for exclude in exclude_paths:
2852 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2853 skip = True
2854 break
2855 if skip:
2856 continue
2857 AddPatternToCheck(f, pattern)
2858 break
2859
2860 return to_check
2861
2862
2863def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
2864 """Adds OWNERS files to check for correct Fuchsia security owners."""
2865
2866 file_patterns = [
2867 # Component specifications.
2868 '*.cml', # Component Framework v2.
2869 '*.cmx', # Component Framework v1.
2870
2871 # Fuchsia IDL protocol specifications.
2872 '*.fidl',
2873 ]
2874
2875 # Don't check for owners files for changes in these directories.
2876 exclude_paths = [
2877 'third_party/crashpad/*',
2878 ]
2879
2880 def AddPatternToCheck(input_file, pattern):
2881 owners_file = input_api.os_path.join(
2882 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2883 if owners_file not in to_check:
2884 to_check[owners_file] = {}
2885 if pattern not in to_check[owners_file]:
2886 to_check[owners_file][pattern] = {
2887 'files': [],
2888 'rules': [
2889 'per-file %s=set noparent' % pattern,
2890 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
2891 ]
2892 }
2893 to_check[owners_file][pattern]['files'].append(input_file)
2894
2895 # Iterate through the affected files to see what we actually need to check
2896 # for. We should only nag patch authors about per-file rules if a file in that
2897 # directory would match that pattern.
2898 for f in input_api.AffectedFiles(include_deletes=False):
2899 skip = False
2900 for exclude in exclude_paths:
2901 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2902 skip = True
2903 if skip:
2904 continue
2905
2906 for pattern in file_patterns:
2907 if input_api.fnmatch.fnmatch(
2908 input_api.os_path.basename(f.LocalPath()), pattern):
2909 AddPatternToCheck(f, pattern)
2910 break
2911
2912 return to_check
2913
2914
2915def CheckSecurityOwners(input_api, output_api):
2916 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2917 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2918 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
2919
2920 if to_check:
2921 # If there are any OWNERS files to check, there are IPC-related changes in
2922 # this CL. Auto-CC the review list.
2923 output_api.AppendCC('[email protected]')
2924
2925 # Go through the OWNERS files to check, filtering out rules that are already
2926 # present in that OWNERS file.
2927 for owners_file, patterns in to_check.items():
2928 try:
2929 with open(owners_file) as f:
2930 lines = set(f.read().splitlines())
2931 for entry in patterns.values():
2932 entry['rules'] = [
2933 rule for rule in entry['rules'] if rule not in lines
2934 ]
2935 except IOError:
2936 # No OWNERS file, so all the rules are definitely missing.
2937 continue
2938
2939 # All the remaining lines weren't found in OWNERS files, so emit an error.
2940 errors = []
2941 for owners_file, patterns in to_check.items():
2942 missing_lines = []
2943 files = []
2944 for _, entry in patterns.items():
2945 missing_lines.extend(entry['rules'])
2946 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2947 if missing_lines:
2948 errors.append('Because of the presence of files:\n%s\n\n'
2949 '%s needs the following %d lines added:\n\n%s' %
2950 ('\n'.join(files), owners_file, len(missing_lines),
2951 '\n'.join(missing_lines)))
2952
2953 results = []
2954 if errors:
2955 if input_api.is_committing:
2956 output = output_api.PresubmitError
2957 else:
2958 output = output_api.PresubmitPromptWarning
2959 results.append(
2960 output(
2961 'Found OWNERS files that need to be updated for IPC security '
2962 + 'review coverage.\nPlease update the OWNERS files below:',
2963 long_text='\n\n'.join(errors)))
2964
2965 return results
2966
2967
2968def _GetFilesUsingSecurityCriticalFunctions(input_api):
2969 """Checks affected files for changes to security-critical calls. This
2970 function checks the full change diff, to catch both additions/changes
2971 and removals.
2972
2973 Returns a dict keyed by file name, and the value is a set of detected
2974 functions.
2975 """
2976 # Map of function pretty name (displayed in an error) to the pattern to
2977 # match it with.
2978 _PATTERNS_TO_CHECK = {
2979 'content::GetServiceSandboxType<>()': 'GetServiceSandboxType\\<'
2980 }
2981 _PATTERNS_TO_CHECK = {
2982 k: input_api.re.compile(v)
2983 for k, v in _PATTERNS_TO_CHECK.items()
2984 }
2985
John Budorick47ca3fe2018-02-10 00:53:102986 import os
2987
Sam Maiera6e76d72022-02-11 21:43:502988 # We don't want to trigger on strings within this file.
2989 def presubmit_file_filter(f):
2990 return 'PRESUBMIT.py' != os.path.split(f.LocalPath())[1]
2991
2992 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
2993 files_to_functions = {}
2994 for f in input_api.AffectedFiles(file_filter=presubmit_file_filter):
2995 diff = f.GenerateScmDiff()
2996 for line in diff.split('\n'):
2997 # Not using just RightHandSideLines() because removing a
2998 # call to a security-critical function can be just as important
2999 # as adding or changing the arguments.
3000 if line.startswith('-') or (line.startswith('+')
3001 and not line.startswith('++')):
3002 for name, pattern in _PATTERNS_TO_CHECK.items():
3003 if pattern.search(line):
3004 path = f.LocalPath()
3005 if not path in files_to_functions:
3006 files_to_functions[path] = set()
3007 files_to_functions[path].add(name)
3008 return files_to_functions
3009
3010
3011def CheckSecurityChanges(input_api, output_api):
3012 """Checks that changes involving security-critical functions are reviewed
3013 by the security team.
3014 """
3015 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3016 if not len(files_to_functions):
3017 return []
3018
3019 owner_email, reviewers = (
3020 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3021 input_api, None, approval_needed=input_api.is_committing))
3022
3023 # Load the OWNERS file for security changes.
3024 owners_file = 'ipc/SECURITY_OWNERS'
3025 security_owners = input_api.owners_client.ListOwners(owners_file)
3026 has_security_owner = any([owner in reviewers for owner in security_owners])
3027 if has_security_owner:
3028 return []
3029
3030 msg = 'The following files change calls to security-sensive functions\n' \
3031 'that need to be reviewed by {}.\n'.format(owners_file)
3032 for path, names in files_to_functions.items():
3033 msg += ' {}\n'.format(path)
3034 for name in names:
3035 msg += ' {}\n'.format(name)
3036 msg += '\n'
3037
3038 if input_api.is_committing:
3039 output = output_api.PresubmitError
Mohamed Heikale217fc852020-07-06 19:44:033040 else:
Sam Maiera6e76d72022-02-11 21:43:503041 output = output_api.PresubmitNotifyResult
3042 return [output(msg)]
3043
3044
3045def CheckSetNoParent(input_api, output_api):
3046 """Checks that set noparent is only used together with an OWNERS file in
3047 //build/OWNERS.setnoparent (see also
3048 //docs/code_reviews.md#owners-files-details)
3049 """
3050 # Return early if no OWNERS files were modified.
3051 if not any(f.LocalPath().endswith('OWNERS')
3052 for f in input_api.AffectedFiles(include_deletes=False)):
3053 return []
3054
3055 errors = []
3056
3057 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3058 allowed_owners_files = set()
3059 with open(allowed_owners_files_file, 'r') as f:
3060 for line in f:
3061 line = line.strip()
3062 if not line or line.startswith('#'):
3063 continue
3064 allowed_owners_files.add(line)
3065
3066 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3067
3068 for f in input_api.AffectedFiles(include_deletes=False):
3069 if not f.LocalPath().endswith('OWNERS'):
3070 continue
3071
3072 found_owners_files = set()
3073 found_set_noparent_lines = dict()
3074
3075 # Parse the OWNERS file.
3076 for lineno, line in enumerate(f.NewContents(), 1):
3077 line = line.strip()
3078 if line.startswith('set noparent'):
3079 found_set_noparent_lines[''] = lineno
3080 if line.startswith('file://'):
3081 if line in allowed_owners_files:
3082 found_owners_files.add('')
3083 if line.startswith('per-file'):
3084 match = per_file_pattern.match(line)
3085 if match:
3086 glob = match.group(1).strip()
3087 directive = match.group(2).strip()
3088 if directive == 'set noparent':
3089 found_set_noparent_lines[glob] = lineno
3090 if directive.startswith('file://'):
3091 if directive in allowed_owners_files:
3092 found_owners_files.add(glob)
3093
3094 # Check that every set noparent line has a corresponding file:// line
3095 # listed in build/OWNERS.setnoparent. An exception is made for top level
3096 # directories since src/OWNERS shouldn't review them.
Bruce Dawson6bb0d672022-04-06 15:13:493097 linux_path = f.LocalPath().replace(input_api.os_path.sep, '/')
3098 if (linux_path.count('/') != 1
3099 and (not linux_path in _EXCLUDED_SET_NO_PARENT_PATHS)):
Sam Maiera6e76d72022-02-11 21:43:503100 for set_noparent_line in found_set_noparent_lines:
3101 if set_noparent_line in found_owners_files:
3102 continue
3103 errors.append(' %s:%d' %
Bruce Dawson6bb0d672022-04-06 15:13:493104 (linux_path,
Sam Maiera6e76d72022-02-11 21:43:503105 found_set_noparent_lines[set_noparent_line]))
3106
3107 results = []
3108 if errors:
3109 if input_api.is_committing:
3110 output = output_api.PresubmitError
3111 else:
3112 output = output_api.PresubmitPromptWarning
3113 results.append(
3114 output(
3115 'Found the following "set noparent" restrictions in OWNERS files that '
3116 'do not include owners from build/OWNERS.setnoparent:',
3117 long_text='\n\n'.join(errors)))
3118 return results
3119
3120
3121def CheckUselessForwardDeclarations(input_api, output_api):
3122 """Checks that added or removed lines in non third party affected
3123 header files do not lead to new useless class or struct forward
3124 declaration.
3125 """
3126 results = []
3127 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3128 input_api.re.MULTILINE)
3129 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3130 input_api.re.MULTILINE)
3131 for f in input_api.AffectedFiles(include_deletes=False):
3132 if (f.LocalPath().startswith('third_party')
3133 and not f.LocalPath().startswith('third_party/blink')
3134 and not f.LocalPath().startswith('third_party\\blink')):
3135 continue
3136
3137 if not f.LocalPath().endswith('.h'):
3138 continue
3139
3140 contents = input_api.ReadFile(f)
3141 fwd_decls = input_api.re.findall(class_pattern, contents)
3142 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3143
3144 useless_fwd_decls = []
3145 for decl in fwd_decls:
3146 count = sum(1 for _ in input_api.re.finditer(
3147 r'\b%s\b' % input_api.re.escape(decl), contents))
3148 if count == 1:
3149 useless_fwd_decls.append(decl)
3150
3151 if not useless_fwd_decls:
3152 continue
3153
3154 for line in f.GenerateScmDiff().splitlines():
3155 if (line.startswith('-') and not line.startswith('--')
3156 or line.startswith('+') and not line.startswith('++')):
3157 for decl in useless_fwd_decls:
3158 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3159 results.append(
3160 output_api.PresubmitPromptWarning(
3161 '%s: %s forward declaration is no longer needed'
3162 % (f.LocalPath(), decl)))
3163 useless_fwd_decls.remove(decl)
3164
3165 return results
3166
3167
3168def _CheckAndroidDebuggableBuild(input_api, output_api):
3169 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3170 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3171 this is a debuggable build of Android.
3172 """
3173 build_type_check_pattern = input_api.re.compile(
3174 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3175
3176 errors = []
3177
3178 sources = lambda affected_file: input_api.FilterSourceFile(
3179 affected_file,
3180 files_to_skip=(
3181 _EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3182 DEFAULT_FILES_TO_SKIP + (
3183 r"^android_webview[\\/]support_library[\\/]"
3184 "boundary_interfaces[\\/]",
3185 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3186 r'^third_party[\\/].*',
3187 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3188 r"webview[\\/]chromium[\\/]License.*",
3189 )),
3190 files_to_check=[r'.*\.java$'])
3191
3192 for f in input_api.AffectedSourceFiles(sources):
3193 for line_num, line in f.ChangedContents():
3194 if build_type_check_pattern.search(line):
3195 errors.append("%s:%d" % (f.LocalPath(), line_num))
3196
3197 results = []
3198
3199 if errors:
3200 results.append(
3201 output_api.PresubmitPromptWarning(
3202 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3203 ' Please use BuildInfo.isDebugAndroid() instead.', errors))
3204
3205 return results
3206
3207# TODO: add unit tests
3208def _CheckAndroidToastUsage(input_api, output_api):
3209 """Checks that code uses org.chromium.ui.widget.Toast instead of
3210 android.widget.Toast (Chromium Toast doesn't force hardware
3211 acceleration on low-end devices, saving memory).
3212 """
3213 toast_import_pattern = input_api.re.compile(
3214 r'^import android\.widget\.Toast;$')
3215
3216 errors = []
3217
3218 sources = lambda affected_file: input_api.FilterSourceFile(
3219 affected_file,
3220 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3221 DEFAULT_FILES_TO_SKIP + (r'^chromecast[\\/].*',
3222 r'^remoting[\\/].*')),
3223 files_to_check=[r'.*\.java$'])
3224
3225 for f in input_api.AffectedSourceFiles(sources):
3226 for line_num, line in f.ChangedContents():
3227 if toast_import_pattern.search(line):
3228 errors.append("%s:%d" % (f.LocalPath(), line_num))
3229
3230 results = []
3231
3232 if errors:
3233 results.append(
3234 output_api.PresubmitError(
3235 'android.widget.Toast usage is detected. Android toasts use hardware'
3236 ' acceleration, and can be\ncostly on low-end devices. Please use'
3237 ' org.chromium.ui.widget.Toast instead.\n'
3238 'Contact [email protected] if you have any questions.',
3239 errors))
3240
3241 return results
3242
3243
3244def _CheckAndroidCrLogUsage(input_api, output_api):
3245 """Checks that new logs using org.chromium.base.Log:
3246 - Are using 'TAG' as variable name for the tags (warn)
3247 - Are using a tag that is shorter than 20 characters (error)
3248 """
3249
3250 # Do not check format of logs in the given files
3251 cr_log_check_excluded_paths = [
3252 # //chrome/android/webapk cannot depend on //base
3253 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3254 # WebView license viewer code cannot depend on //base; used in stub APK.
3255 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3256 r"webview[\\/]chromium[\\/]License.*",
3257 # The customtabs_benchmark is a small app that does not depend on Chromium
3258 # java pieces.
3259 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3260 ]
3261
3262 cr_log_import_pattern = input_api.re.compile(
3263 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3264 class_in_base_pattern = input_api.re.compile(
3265 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3266 has_some_log_import_pattern = input_api.re.compile(r'^import .*\.Log;$',
3267 input_api.re.MULTILINE)
3268 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
3269 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
3270 log_decl_pattern = input_api.re.compile(
3271 r'static final String TAG = "(?P<name>(.*))"')
3272 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
3273
3274 REF_MSG = ('See docs/android_logging.md for more info.')
3275 sources = lambda x: input_api.FilterSourceFile(
3276 x,
3277 files_to_check=[r'.*\.java$'],
3278 files_to_skip=cr_log_check_excluded_paths)
3279
3280 tag_decl_errors = []
3281 tag_length_errors = []
3282 tag_errors = []
3283 tag_with_dot_errors = []
3284 util_log_errors = []
3285
3286 for f in input_api.AffectedSourceFiles(sources):
3287 file_content = input_api.ReadFile(f)
3288 has_modified_logs = False
3289 # Per line checks
3290 if (cr_log_import_pattern.search(file_content)
3291 or (class_in_base_pattern.search(file_content)
3292 and not has_some_log_import_pattern.search(file_content))):
3293 # Checks to run for files using cr log
3294 for line_num, line in f.ChangedContents():
3295 if rough_log_decl_pattern.search(line):
3296 has_modified_logs = True
3297
3298 # Check if the new line is doing some logging
3299 match = log_call_pattern.search(line)
3300 if match:
3301 has_modified_logs = True
3302
3303 # Make sure it uses "TAG"
3304 if not match.group('tag') == 'TAG':
3305 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
3306 else:
3307 # Report non cr Log function calls in changed lines
3308 for line_num, line in f.ChangedContents():
3309 if log_call_pattern.search(line):
3310 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
3311
3312 # Per file checks
3313 if has_modified_logs:
3314 # Make sure the tag is using the "cr" prefix and is not too long
3315 match = log_decl_pattern.search(file_content)
3316 tag_name = match.group('name') if match else None
3317 if not tag_name:
3318 tag_decl_errors.append(f.LocalPath())
3319 elif len(tag_name) > 20:
3320 tag_length_errors.append(f.LocalPath())
3321 elif '.' in tag_name:
3322 tag_with_dot_errors.append(f.LocalPath())
3323
3324 results = []
3325 if tag_decl_errors:
3326 results.append(
3327 output_api.PresubmitPromptWarning(
3328 'Please define your tags using the suggested format: .\n'
3329 '"private static final String TAG = "<package tag>".\n'
3330 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
3331 tag_decl_errors))
3332
3333 if tag_length_errors:
3334 results.append(
3335 output_api.PresubmitError(
3336 'The tag length is restricted by the system to be at most '
3337 '20 characters.\n' + REF_MSG, tag_length_errors))
3338
3339 if tag_errors:
3340 results.append(
3341 output_api.PresubmitPromptWarning(
3342 'Please use a variable named "TAG" for your log tags.\n' +
3343 REF_MSG, tag_errors))
3344
3345 if util_log_errors:
3346 results.append(
3347 output_api.PresubmitPromptWarning(
3348 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3349 util_log_errors))
3350
3351 if tag_with_dot_errors:
3352 results.append(
3353 output_api.PresubmitPromptWarning(
3354 'Dot in log tags cause them to be elided in crash reports.\n' +
3355 REF_MSG, tag_with_dot_errors))
3356
3357 return results
3358
3359
3360def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3361 """Checks that junit.framework.* is no longer used."""
3362 deprecated_junit_framework_pattern = input_api.re.compile(
3363 r'^import junit\.framework\..*;', input_api.re.MULTILINE)
3364 sources = lambda x: input_api.FilterSourceFile(
3365 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3366 errors = []
3367 for f in input_api.AffectedFiles(file_filter=sources):
3368 for line_num, line in f.ChangedContents():
3369 if deprecated_junit_framework_pattern.search(line):
3370 errors.append("%s:%d" % (f.LocalPath(), line_num))
3371
3372 results = []
3373 if errors:
3374 results.append(
3375 output_api.PresubmitError(
3376 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3377 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3378 ' if you have any question.', errors))
3379 return results
3380
3381
3382def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3383 """Checks that if new Java test classes have inheritance.
3384 Either the new test class is JUnit3 test or it is a JUnit4 test class
3385 with a base class, either case is undesirable.
3386 """
3387 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3388
3389 sources = lambda x: input_api.FilterSourceFile(
3390 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
3391 errors = []
3392 for f in input_api.AffectedFiles(file_filter=sources):
3393 if not f.OldContents():
3394 class_declaration_start_flag = False
3395 for line_num, line in f.ChangedContents():
3396 if class_declaration_pattern.search(line):
3397 class_declaration_start_flag = True
3398 if class_declaration_start_flag and ' extends ' in line:
3399 errors.append('%s:%d' % (f.LocalPath(), line_num))
3400 if '{' in line:
3401 class_declaration_start_flag = False
3402
3403 results = []
3404 if errors:
3405 results.append(
3406 output_api.PresubmitPromptWarning(
3407 'The newly created files include Test classes that inherits from base'
3408 ' class. Please do not use inheritance in JUnit4 tests or add new'
3409 ' JUnit3 tests. Contact [email protected] if you have any'
3410 ' questions.', errors))
3411 return results
3412
3413
3414def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3415 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3416 deprecated_annotation_import_pattern = input_api.re.compile(
3417 r'^import android\.test\.suitebuilder\.annotation\..*;',
3418 input_api.re.MULTILINE)
3419 sources = lambda x: input_api.FilterSourceFile(
3420 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
3421 errors = []
3422 for f in input_api.AffectedFiles(file_filter=sources):
3423 for line_num, line in f.ChangedContents():
3424 if deprecated_annotation_import_pattern.search(line):
3425 errors.append("%s:%d" % (f.LocalPath(), line_num))
3426
3427 results = []
3428 if errors:
3429 results.append(
3430 output_api.PresubmitError(
3431 'Annotations in android.test.suitebuilder.annotation have been'
3432 ' deprecated since API level 24. Please use android.support.test.filters'
3433 ' from //third_party/android_support_test_runner:runner_java instead.'
3434 ' Contact [email protected] if you have any questions.',
3435 errors))
3436 return results
3437
3438
3439def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3440 """Checks if MDPI assets are placed in a correct directory."""
3441 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3442 ('/res/drawable/' in f.LocalPath() or
3443 '/res/drawable-ldrtl/' in f.LocalPath()))
3444 errors = []
3445 for f in input_api.AffectedFiles(include_deletes=False,
3446 file_filter=file_filter):
3447 errors.append(' %s' % f.LocalPath())
3448
3449 results = []
3450 if errors:
3451 results.append(
3452 output_api.PresubmitError(
3453 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3454 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3455 '/res/drawable-ldrtl/.\n'
3456 'Contact [email protected] if you have questions.', errors))
3457 return results
3458
3459
3460def _CheckAndroidWebkitImports(input_api, output_api):
3461 """Checks that code uses org.chromium.base.Callback instead of
3462 android.webview.ValueCallback except in the WebView glue layer
3463 and WebLayer.
3464 """
3465 valuecallback_import_pattern = input_api.re.compile(
3466 r'^import android\.webkit\.ValueCallback;$')
3467
3468 errors = []
3469
3470 sources = lambda affected_file: input_api.FilterSourceFile(
3471 affected_file,
3472 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS + input_api.
3473 DEFAULT_FILES_TO_SKIP + (
3474 r'^android_webview[\\/]glue[\\/].*',
3475 r'^weblayer[\\/].*',
3476 )),
3477 files_to_check=[r'.*\.java$'])
3478
3479 for f in input_api.AffectedSourceFiles(sources):
3480 for line_num, line in f.ChangedContents():
3481 if valuecallback_import_pattern.search(line):
3482 errors.append("%s:%d" % (f.LocalPath(), line_num))
3483
3484 results = []
3485
3486 if errors:
3487 results.append(
3488 output_api.PresubmitError(
3489 'android.webkit.ValueCallback usage is detected outside of the glue'
3490 ' layer. To stay compatible with the support library, android.webkit.*'
3491 ' classes should only be used inside the glue layer and'
3492 ' org.chromium.base.Callback should be used instead.', errors))
3493
3494 return results
3495
3496
3497def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3498 """Checks Android XML styles """
3499
3500 # Return early if no relevant files were modified.
3501 if not any(
3502 _IsXmlOrGrdFile(input_api, f.LocalPath())
3503 for f in input_api.AffectedFiles(include_deletes=False)):
3504 return []
3505
3506 import sys
3507 original_sys_path = sys.path
3508 try:
3509 sys.path = sys.path + [
3510 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3511 'android', 'checkxmlstyle')
3512 ]
3513 import checkxmlstyle
3514 finally:
3515 # Restore sys.path to what it was before.
3516 sys.path = original_sys_path
3517
3518 if is_check_on_upload:
3519 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3520 else:
3521 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3522
3523
3524def _CheckAndroidInfoBarDeprecation(input_api, output_api):
3525 """Checks Android Infobar Deprecation """
3526
3527 import sys
3528 original_sys_path = sys.path
3529 try:
3530 sys.path = sys.path + [
3531 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
3532 'android', 'infobar_deprecation')
3533 ]
3534 import infobar_deprecation
3535 finally:
3536 # Restore sys.path to what it was before.
3537 sys.path = original_sys_path
3538
3539 return infobar_deprecation.CheckDeprecationOnUpload(input_api, output_api)
3540
3541
3542class _PydepsCheckerResult:
3543 def __init__(self, cmd, pydeps_path, process, old_contents):
3544 self._cmd = cmd
3545 self._pydeps_path = pydeps_path
3546 self._process = process
3547 self._old_contents = old_contents
3548
3549 def GetError(self):
3550 """Returns an error message, or None."""
3551 import difflib
3552 if self._process.wait() != 0:
3553 # STDERR should already be printed.
3554 return 'Command failed: ' + self._cmd
3555 new_contents = self._process.stdout.read().splitlines()[2:]
3556 if self._old_contents != new_contents:
3557 diff = '\n'.join(
3558 difflib.context_diff(self._old_contents, new_contents))
3559 return ('File is stale: {}\n'
3560 'Diff (apply to fix):\n'
3561 '{}\n'
3562 'To regenerate, run:\n\n'
3563 ' {}').format(self._pydeps_path, diff, self._cmd)
3564 return None
3565
3566
3567class PydepsChecker:
3568 def __init__(self, input_api, pydeps_files):
3569 self._file_cache = {}
3570 self._input_api = input_api
3571 self._pydeps_files = pydeps_files
3572
3573 def _LoadFile(self, path):
3574 """Returns the list of paths within a .pydeps file relative to //."""
3575 if path not in self._file_cache:
3576 with open(path, encoding='utf-8') as f:
3577 self._file_cache[path] = f.read()
3578 return self._file_cache[path]
3579
3580 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3581 """Returns an interable of paths within the .pydep, relativized to //."""
3582 pydeps_data = self._LoadFile(pydeps_path)
3583 uses_gn_paths = '--gn-paths' in pydeps_data
3584 entries = (l for l in pydeps_data.splitlines()
3585 if not l.startswith('#'))
3586 if uses_gn_paths:
3587 # Paths look like: //foo/bar/baz
3588 return (e[2:] for e in entries)
3589 else:
3590 # Paths look like: path/relative/to/file.pydeps
3591 os_path = self._input_api.os_path
3592 pydeps_dir = os_path.dirname(pydeps_path)
3593 return (os_path.normpath(os_path.join(pydeps_dir, e))
3594 for e in entries)
3595
3596 def _CreateFilesToPydepsMap(self):
3597 """Returns a map of local_path -> list_of_pydeps."""
3598 ret = {}
3599 for pydep_local_path in self._pydeps_files:
3600 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3601 ret.setdefault(path, []).append(pydep_local_path)
3602 return ret
3603
3604 def ComputeAffectedPydeps(self):
3605 """Returns an iterable of .pydeps files that might need regenerating."""
3606 affected_pydeps = set()
3607 file_to_pydeps_map = None
3608 for f in self._input_api.AffectedFiles(include_deletes=True):
3609 local_path = f.LocalPath()
3610 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3611 # subrepositories. We can't figure out which files change, so re-check
3612 # all files.
3613 # Changes to print_python_deps.py affect all .pydeps.
3614 if local_path in ('DEPS', 'PRESUBMIT.py'
3615 ) or local_path.endswith('print_python_deps.py'):
3616 return self._pydeps_files
3617 elif local_path.endswith('.pydeps'):
3618 if local_path in self._pydeps_files:
3619 affected_pydeps.add(local_path)
3620 elif local_path.endswith('.py'):
3621 if file_to_pydeps_map is None:
3622 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3623 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3624 return affected_pydeps
3625
3626 def DetermineIfStaleAsync(self, pydeps_path):
3627 """Runs print_python_deps.py to see if the files is stale."""
3628 import os
3629
3630 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
3631 if old_pydeps_data:
3632 cmd = old_pydeps_data[1][1:].strip()
3633 if '--output' not in cmd:
3634 cmd += ' --output ' + pydeps_path
3635 old_contents = old_pydeps_data[2:]
3636 else:
3637 # A default cmd that should work in most cases (as long as pydeps filename
3638 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3639 # file is empty/new.
3640 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3641 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3642 old_contents = []
3643 env = dict(os.environ)
3644 env['PYTHONDONTWRITEBYTECODE'] = '1'
3645 process = self._input_api.subprocess.Popen(
3646 cmd + ' --output ""',
3647 shell=True,
3648 env=env,
3649 stdout=self._input_api.subprocess.PIPE,
3650 encoding='utf-8')
3651 return _PydepsCheckerResult(cmd, pydeps_path, process, old_contents)
agrievef32bcc72016-04-04 14:57:403652
3653
Tibor Goldschwendt360793f72019-06-25 18:23:493654def _ParseGclientArgs():
Sam Maiera6e76d72022-02-11 21:43:503655 args = {}
3656 with open('build/config/gclient_args.gni', 'r') as f:
3657 for line in f:
3658 line = line.strip()
3659 if not line or line.startswith('#'):
3660 continue
3661 attribute, value = line.split('=')
3662 args[attribute.strip()] = value.strip()
3663 return args
Tibor Goldschwendt360793f72019-06-25 18:23:493664
3665
Saagar Sanghavifceeaae2020-08-12 16:40:363666def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
Sam Maiera6e76d72022-02-11 21:43:503667 """Checks if a .pydeps file needs to be regenerated."""
3668 # This check is for Python dependency lists (.pydeps files), and involves
3669 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3670 # doesn't work on Windows and Mac, so skip it on other platforms.
3671 if not input_api.platform.startswith('linux'):
3672 return []
Erik Staabc734cd7a2021-11-23 03:11:523673
Sam Maiera6e76d72022-02-11 21:43:503674 results = []
3675 # First, check for new / deleted .pydeps.
3676 for f in input_api.AffectedFiles(include_deletes=True):
3677 # Check whether we are running the presubmit check for a file in src.
3678 # f.LocalPath is relative to repo (src, or internal repo).
3679 # os_path.exists is relative to src repo.
3680 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3681 # to src and we can conclude that the pydeps is in src.
3682 if f.LocalPath().endswith('.pydeps'):
3683 if input_api.os_path.exists(f.LocalPath()):
3684 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3685 results.append(
3686 output_api.PresubmitError(
3687 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3688 'remove %s' % f.LocalPath()))
3689 elif f.Action() != 'D' and f.LocalPath(
3690 ) not in _ALL_PYDEPS_FILES:
3691 results.append(
3692 output_api.PresubmitError(
3693 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3694 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403695
Sam Maiera6e76d72022-02-11 21:43:503696 if results:
3697 return results
3698
3699 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
3700 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3701 affected_pydeps = set(checker.ComputeAffectedPydeps())
3702 affected_android_pydeps = affected_pydeps.intersection(
3703 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3704 if affected_android_pydeps and not is_android:
3705 results.append(
3706 output_api.PresubmitPromptOrNotify(
3707 'You have changed python files that may affect pydeps for android\n'
3708 'specific scripts. However, the relevant presumbit check cannot be\n'
3709 'run because you are not using an Android checkout. To validate that\n'
3710 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3711 'use the android-internal-presubmit optional trybot.\n'
3712 'Possibly stale pydeps files:\n{}'.format(
3713 '\n'.join(affected_android_pydeps))))
3714
3715 all_pydeps = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
3716 pydeps_to_check = affected_pydeps.intersection(all_pydeps)
3717 # Process these concurrently, as each one takes 1-2 seconds.
3718 pydep_results = [checker.DetermineIfStaleAsync(p) for p in pydeps_to_check]
3719 for result in pydep_results:
3720 error_msg = result.GetError()
3721 if error_msg:
3722 results.append(output_api.PresubmitError(error_msg))
3723
agrievef32bcc72016-04-04 14:57:403724 return results
3725
agrievef32bcc72016-04-04 14:57:403726
Saagar Sanghavifceeaae2020-08-12 16:40:363727def CheckSingletonInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503728 """Checks to make sure no header files have |Singleton<|."""
3729
3730 def FileFilter(affected_file):
3731 # It's ok for base/memory/singleton.h to have |Singleton<|.
3732 files_to_skip = (_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
3733 (r"^base[\\/]memory[\\/]singleton\.h$",
3734 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
James Cook24a504192020-07-23 00:08:443735 r"quic_singleton_impl\.h$"))
Sam Maiera6e76d72022-02-11 21:43:503736 return input_api.FilterSourceFile(affected_file,
3737 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433738
Sam Maiera6e76d72022-02-11 21:43:503739 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
3740 files = []
3741 for f in input_api.AffectedSourceFiles(FileFilter):
3742 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx')
3743 or f.LocalPath().endswith('.hpp')
3744 or f.LocalPath().endswith('.inl')):
3745 contents = input_api.ReadFile(f)
3746 for line in contents.splitlines(False):
3747 if (not line.lstrip().startswith('//')
3748 and # Strip C++ comment.
3749 pattern.search(line)):
3750 files.append(f)
3751 break
glidere61efad2015-02-18 17:39:433752
Sam Maiera6e76d72022-02-11 21:43:503753 if files:
3754 return [
3755 output_api.PresubmitError(
3756 'Found base::Singleton<T> in the following header files.\n' +
3757 'Please move them to an appropriate source file so that the ' +
3758 'template gets instantiated in a single compilation unit.',
3759 files)
3760 ]
3761 return []
glidere61efad2015-02-18 17:39:433762
3763
[email protected]fd20b902014-05-09 02:14:533764_DEPRECATED_CSS = [
3765 # Values
3766 ( "-webkit-box", "flex" ),
3767 ( "-webkit-inline-box", "inline-flex" ),
3768 ( "-webkit-flex", "flex" ),
3769 ( "-webkit-inline-flex", "inline-flex" ),
3770 ( "-webkit-min-content", "min-content" ),
3771 ( "-webkit-max-content", "max-content" ),
3772
3773 # Properties
3774 ( "-webkit-background-clip", "background-clip" ),
3775 ( "-webkit-background-origin", "background-origin" ),
3776 ( "-webkit-background-size", "background-size" ),
3777 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443778 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533779
3780 # Functions
3781 ( "-webkit-gradient", "gradient" ),
3782 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3783 ( "-webkit-linear-gradient", "linear-gradient" ),
3784 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3785 ( "-webkit-radial-gradient", "radial-gradient" ),
3786 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3787]
3788
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203789
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493790# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363791def CheckNoDeprecatedCss(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503792 """ Make sure that we don't use deprecated CSS
3793 properties, functions or values. Our external
3794 documentation and iOS CSS for dom distiller
3795 (reader mode) are ignored by the hooks as it
3796 needs to be consumed by WebKit. """
3797 results = []
3798 file_inclusion_pattern = [r".+\.css$"]
3799 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
3800 input_api.DEFAULT_FILES_TO_SKIP +
3801 (r"^chrome/common/extensions/docs", r"^chrome/docs",
3802 r"^native_client_sdk"))
3803 file_filter = lambda f: input_api.FilterSourceFile(
3804 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
3805 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3806 for line_num, line in fpath.ChangedContents():
3807 for (deprecated_value, value) in _DEPRECATED_CSS:
3808 if deprecated_value in line:
3809 results.append(
3810 output_api.PresubmitError(
3811 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3812 (fpath.LocalPath(), line_num, deprecated_value,
3813 value)))
3814 return results
[email protected]fd20b902014-05-09 02:14:533815
mohan.reddyf21db962014-10-16 12:26:473816
Saagar Sanghavifceeaae2020-08-12 16:40:363817def CheckForRelativeIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503818 bad_files = {}
3819 for f in input_api.AffectedFiles(include_deletes=False):
3820 if (f.LocalPath().startswith('third_party')
3821 and not f.LocalPath().startswith('third_party/blink')
3822 and not f.LocalPath().startswith('third_party\\blink')):
3823 continue
rlanday6802cf632017-05-30 17:48:363824
Sam Maiera6e76d72022-02-11 21:43:503825 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3826 continue
rlanday6802cf632017-05-30 17:48:363827
Sam Maiera6e76d72022-02-11 21:43:503828 relative_includes = [
3829 line for _, line in f.ChangedContents()
3830 if "#include" in line and "../" in line
3831 ]
3832 if not relative_includes:
3833 continue
3834 bad_files[f.LocalPath()] = relative_includes
rlanday6802cf632017-05-30 17:48:363835
Sam Maiera6e76d72022-02-11 21:43:503836 if not bad_files:
3837 return []
rlanday6802cf632017-05-30 17:48:363838
Sam Maiera6e76d72022-02-11 21:43:503839 error_descriptions = []
3840 for file_path, bad_lines in bad_files.items():
3841 error_description = file_path
3842 for line in bad_lines:
3843 error_description += '\n ' + line
3844 error_descriptions.append(error_description)
rlanday6802cf632017-05-30 17:48:363845
Sam Maiera6e76d72022-02-11 21:43:503846 results = []
3847 results.append(
3848 output_api.PresubmitError(
3849 'You added one or more relative #include paths (including "../").\n'
3850 'These shouldn\'t be used because they can be used to include headers\n'
3851 'from code that\'s not correctly specified as a dependency in the\n'
3852 'relevant BUILD.gn file(s).', error_descriptions))
rlanday6802cf632017-05-30 17:48:363853
Sam Maiera6e76d72022-02-11 21:43:503854 return results
rlanday6802cf632017-05-30 17:48:363855
Takeshi Yoshinoe387aa32017-08-02 13:16:133856
Saagar Sanghavifceeaae2020-08-12 16:40:363857def CheckForCcIncludes(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503858 """Check that nobody tries to include a cc file. It's a relatively
3859 common error which results in duplicate symbols in object
3860 files. This may not always break the build until someone later gets
3861 very confusing linking errors."""
3862 results = []
3863 for f in input_api.AffectedFiles(include_deletes=False):
3864 # We let third_party code do whatever it wants
3865 if (f.LocalPath().startswith('third_party')
3866 and not f.LocalPath().startswith('third_party/blink')
3867 and not f.LocalPath().startswith('third_party\\blink')):
3868 continue
Daniel Bratell65b033262019-04-23 08:17:063869
Sam Maiera6e76d72022-02-11 21:43:503870 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3871 continue
Daniel Bratell65b033262019-04-23 08:17:063872
Sam Maiera6e76d72022-02-11 21:43:503873 for _, line in f.ChangedContents():
3874 if line.startswith('#include "'):
3875 included_file = line.split('"')[1]
3876 if _IsCPlusPlusFile(input_api, included_file):
3877 # The most common naming for external files with C++ code,
3878 # apart from standard headers, is to call them foo.inc, but
3879 # Chromium sometimes uses foo-inc.cc so allow that as well.
3880 if not included_file.endswith(('.h', '-inc.cc')):
3881 results.append(
3882 output_api.PresubmitError(
3883 'Only header files or .inc files should be included in other\n'
3884 'C++ files. Compiling the contents of a cc file more than once\n'
3885 'will cause duplicate information in the build which may later\n'
3886 'result in strange link_errors.\n' +
3887 f.LocalPath() + ':\n ' + line))
Daniel Bratell65b033262019-04-23 08:17:063888
Sam Maiera6e76d72022-02-11 21:43:503889 return results
Daniel Bratell65b033262019-04-23 08:17:063890
3891
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203892def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
Sam Maiera6e76d72022-02-11 21:43:503893 if not isinstance(key, ast.Str):
3894 return 'Key at line %d must be a string literal' % key.lineno
3895 if not isinstance(value, ast.Dict):
3896 return 'Value at line %d must be a dict' % value.lineno
3897 if len(value.keys) != 1:
3898 return 'Dict at line %d must have single entry' % value.lineno
3899 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3900 return (
3901 'Entry at line %d must have a string literal \'filepath\' as key' %
3902 value.lineno)
3903 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Takeshi Yoshinoe387aa32017-08-02 13:16:133905
Sergey Ulanov4af16052018-11-08 02:41:463906def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Sam Maiera6e76d72022-02-11 21:43:503907 if not isinstance(key, ast.Str):
3908 return 'Key at line %d must be a string literal' % key.lineno
3909 if not isinstance(value, ast.List):
3910 return 'Value at line %d must be a list' % value.lineno
3911 for element in value.elts:
3912 if not isinstance(element, ast.Str):
3913 return 'Watchlist elements on line %d is not a string' % key.lineno
3914 if not email_regex.match(element.s):
3915 return ('Watchlist element on line %d doesn\'t look like a valid '
3916 + 'email: %s') % (key.lineno, element.s)
3917 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133918
Takeshi Yoshinoe387aa32017-08-02 13:16:133919
Sergey Ulanov4af16052018-11-08 02:41:463920def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Sam Maiera6e76d72022-02-11 21:43:503921 mismatch_template = (
3922 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3923 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133924
Sam Maiera6e76d72022-02-11 21:43:503925 email_regex = input_api.re.compile(
3926 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
Sergey Ulanov4af16052018-11-08 02:41:463927
Sam Maiera6e76d72022-02-11 21:43:503928 ast = input_api.ast
3929 i = 0
3930 last_key = ''
3931 while True:
3932 if i >= len(wd_dict.keys):
3933 if i >= len(w_dict.keys):
3934 return None
3935 return mismatch_template % ('missing',
3936 'line %d' % w_dict.keys[i].lineno)
3937 elif i >= len(w_dict.keys):
3938 return (mismatch_template %
3939 ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133940
Sam Maiera6e76d72022-02-11 21:43:503941 wd_key = wd_dict.keys[i]
3942 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133943
Sam Maiera6e76d72022-02-11 21:43:503944 result = _CheckWatchlistDefinitionsEntrySyntax(wd_key,
3945 wd_dict.values[i], ast)
3946 if result is not None:
3947 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133948
Sam Maiera6e76d72022-02-11 21:43:503949 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast,
3950 email_regex)
3951 if result is not None:
3952 return 'Bad entry in WATCHLISTS dict: %s' % result
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203953
Sam Maiera6e76d72022-02-11 21:43:503954 if wd_key.s != w_key.s:
3955 return mismatch_template % ('%s at line %d' %
3956 (wd_key.s, wd_key.lineno),
3957 '%s at line %d' %
3958 (w_key.s, w_key.lineno))
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203959
Sam Maiera6e76d72022-02-11 21:43:503960 if wd_key.s < last_key:
3961 return (
3962 'WATCHLISTS dict is not sorted lexicographically at line %d and %d'
3963 % (wd_key.lineno, w_key.lineno))
3964 last_key = wd_key.s
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203965
Sam Maiera6e76d72022-02-11 21:43:503966 i = i + 1
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203967
3968
Sergey Ulanov4af16052018-11-08 02:41:463969def _CheckWATCHLISTSSyntax(expression, input_api):
Sam Maiera6e76d72022-02-11 21:43:503970 ast = input_api.ast
3971 if not isinstance(expression, ast.Expression):
3972 return 'WATCHLISTS file must contain a valid expression'
3973 dictionary = expression.body
3974 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3975 return 'WATCHLISTS file must have single dict with exactly two entries'
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203976
Sam Maiera6e76d72022-02-11 21:43:503977 first_key = dictionary.keys[0]
3978 first_value = dictionary.values[0]
3979 second_key = dictionary.keys[1]
3980 second_value = dictionary.values[1]
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203981
Sam Maiera6e76d72022-02-11 21:43:503982 if (not isinstance(first_key, ast.Str)
3983 or first_key.s != 'WATCHLIST_DEFINITIONS'
3984 or not isinstance(first_value, ast.Dict)):
3985 return ('The first entry of the dict in WATCHLISTS file must be '
3986 'WATCHLIST_DEFINITIONS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203987
Sam Maiera6e76d72022-02-11 21:43:503988 if (not isinstance(second_key, ast.Str) or second_key.s != 'WATCHLISTS'
3989 or not isinstance(second_value, ast.Dict)):
3990 return ('The second entry of the dict in WATCHLISTS file must be '
3991 'WATCHLISTS dict')
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203992
Sam Maiera6e76d72022-02-11 21:43:503993 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133994
3995
Saagar Sanghavifceeaae2020-08-12 16:40:363996def CheckWATCHLISTS(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:503997 for f in input_api.AffectedFiles(include_deletes=False):
3998 if f.LocalPath() == 'WATCHLISTS':
3999 contents = input_api.ReadFile(f, 'r')
Takeshi Yoshinoe387aa32017-08-02 13:16:134000
Sam Maiera6e76d72022-02-11 21:43:504001 try:
4002 # First, make sure that it can be evaluated.
4003 input_api.ast.literal_eval(contents)
4004 # Get an AST tree for it and scan the tree for detailed style checking.
4005 expression = input_api.ast.parse(contents,
4006 filename='WATCHLISTS',
4007 mode='eval')
4008 except ValueError as e:
4009 return [
4010 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4011 long_text=repr(e))
4012 ]
4013 except SyntaxError as e:
4014 return [
4015 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4016 long_text=repr(e))
4017 ]
4018 except TypeError as e:
4019 return [
4020 output_api.PresubmitError('Cannot parse WATCHLISTS file',
4021 long_text=repr(e))
4022 ]
Takeshi Yoshinoe387aa32017-08-02 13:16:134023
Sam Maiera6e76d72022-02-11 21:43:504024 result = _CheckWATCHLISTSSyntax(expression, input_api)
4025 if result is not None:
4026 return [output_api.PresubmitError(result)]
4027 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134028
Sam Maiera6e76d72022-02-11 21:43:504029 return []
Takeshi Yoshinoe387aa32017-08-02 13:16:134030
4031
Andrew Grieve1b290e4a22020-11-24 20:07:014032def CheckGnGlobForward(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504033 """Checks that forward_variables_from(invoker, "*") follows best practices.
Andrew Grieve1b290e4a22020-11-24 20:07:014034
Sam Maiera6e76d72022-02-11 21:43:504035 As documented at //build/docs/writing_gn_templates.md
4036 """
Andrew Grieve1b290e4a22020-11-24 20:07:014037
Sam Maiera6e76d72022-02-11 21:43:504038 def gn_files(f):
4039 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gni', ))
Andrew Grieve1b290e4a22020-11-24 20:07:014040
Sam Maiera6e76d72022-02-11 21:43:504041 problems = []
4042 for f in input_api.AffectedSourceFiles(gn_files):
4043 for line_num, line in f.ChangedContents():
4044 if 'forward_variables_from(invoker, "*")' in line:
4045 problems.append(
4046 'Bare forward_variables_from(invoker, "*") in %s:%d' %
4047 (f.LocalPath(), line_num))
4048
4049 if problems:
4050 return [
4051 output_api.PresubmitPromptWarning(
4052 'forward_variables_from("*") without exclusions',
4053 items=sorted(problems),
4054 long_text=(
4055 'The variables "visibilty" and "test_only" should be '
4056 'explicitly listed in forward_variables_from(). For more '
4057 'details, see:\n'
4058 'https://chromium.googlesource.com/chromium/src/+/HEAD/'
4059 'build/docs/writing_gn_templates.md'
4060 '#Using-forward_variables_from'))
4061 ]
4062 return []
Andrew Grieve1b290e4a22020-11-24 20:07:014063
4064
Saagar Sanghavifceeaae2020-08-12 16:40:364065def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504066 """Checks that newly added header files have corresponding GN changes.
4067 Note that this is only a heuristic. To be precise, run script:
4068 build/check_gn_headers.py.
4069 """
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194070
Sam Maiera6e76d72022-02-11 21:43:504071 def headers(f):
4072 return input_api.FilterSourceFile(
4073 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194074
Sam Maiera6e76d72022-02-11 21:43:504075 new_headers = []
4076 for f in input_api.AffectedSourceFiles(headers):
4077 if f.Action() != 'A':
4078 continue
4079 new_headers.append(f.LocalPath())
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194080
Sam Maiera6e76d72022-02-11 21:43:504081 def gn_files(f):
4082 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194083
Sam Maiera6e76d72022-02-11 21:43:504084 all_gn_changed_contents = ''
4085 for f in input_api.AffectedSourceFiles(gn_files):
4086 for _, line in f.ChangedContents():
4087 all_gn_changed_contents += line
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194088
Sam Maiera6e76d72022-02-11 21:43:504089 problems = []
4090 for header in new_headers:
4091 basename = input_api.os_path.basename(header)
4092 if basename not in all_gn_changed_contents:
4093 problems.append(header)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194094
Sam Maiera6e76d72022-02-11 21:43:504095 if problems:
4096 return [
4097 output_api.PresubmitPromptWarning(
4098 'Missing GN changes for new header files',
4099 items=sorted(problems),
4100 long_text=
4101 'Please double check whether newly added header files need '
4102 'corresponding changes in gn or gni files.\nThis checking is only a '
4103 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4104 'Read https://crbug.com/661774 for more info.')
4105 ]
4106 return []
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194107
4108
Saagar Sanghavifceeaae2020-08-12 16:40:364109def CheckCorrectProductNameInMessages(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504110 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
Michael Giuffridad3bc8672018-10-25 22:48:024111
Sam Maiera6e76d72022-02-11 21:43:504112 This assumes we won't intentionally reference one product from the other
4113 product.
4114 """
4115 all_problems = []
4116 test_cases = [{
4117 "filename_postfix": "google_chrome_strings.grd",
4118 "correct_name": "Chrome",
4119 "incorrect_name": "Chromium",
4120 }, {
4121 "filename_postfix": "chromium_strings.grd",
4122 "correct_name": "Chromium",
4123 "incorrect_name": "Chrome",
4124 }]
Michael Giuffridad3bc8672018-10-25 22:48:024125
Sam Maiera6e76d72022-02-11 21:43:504126 for test_case in test_cases:
4127 problems = []
4128 filename_filter = lambda x: x.LocalPath().endswith(test_case[
4129 "filename_postfix"])
Michael Giuffridad3bc8672018-10-25 22:48:024130
Sam Maiera6e76d72022-02-11 21:43:504131 # Check each new line. Can yield false positives in multiline comments, but
4132 # easier than trying to parse the XML because messages can have nested
4133 # children, and associating message elements with affected lines is hard.
4134 for f in input_api.AffectedSourceFiles(filename_filter):
4135 for line_num, line in f.ChangedContents():
4136 if "<message" in line or "<!--" in line or "-->" in line:
4137 continue
4138 if test_case["incorrect_name"] in line:
4139 problems.append("Incorrect product name in %s:%d" %
4140 (f.LocalPath(), line_num))
Michael Giuffridad3bc8672018-10-25 22:48:024141
Sam Maiera6e76d72022-02-11 21:43:504142 if problems:
4143 message = (
4144 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4145 % (test_case["correct_name"], test_case["correct_name"],
4146 test_case["incorrect_name"]))
4147 all_problems.append(
4148 output_api.PresubmitPromptWarning(message, items=problems))
Michael Giuffridad3bc8672018-10-25 22:48:024149
Sam Maiera6e76d72022-02-11 21:43:504150 return all_problems
Michael Giuffridad3bc8672018-10-25 22:48:024151
4152
Saagar Sanghavifceeaae2020-08-12 16:40:364153def CheckForTooLargeFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504154 """Avoid large files, especially binary files, in the repository since
4155 git doesn't scale well for those. They will be in everyone's repo
4156 clones forever, forever making Chromium slower to clone and work
4157 with."""
Daniel Bratell93eb6c62019-04-29 20:13:364158
Sam Maiera6e76d72022-02-11 21:43:504159 # Uploading files to cloud storage is not trivial so we don't want
4160 # to set the limit too low, but the upper limit for "normal" large
4161 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4162 # anything over 20 MB is exceptional.
4163 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
Daniel Bratell93eb6c62019-04-29 20:13:364164
Sam Maiera6e76d72022-02-11 21:43:504165 too_large_files = []
4166 for f in input_api.AffectedFiles():
4167 # Check both added and modified files (but not deleted files).
4168 if f.Action() in ('A', 'M'):
4169 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
4170 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4171 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
Daniel Bratell93eb6c62019-04-29 20:13:364172
Sam Maiera6e76d72022-02-11 21:43:504173 if too_large_files:
4174 message = (
4175 'Do not commit large files to git since git scales badly for those.\n'
4176 +
4177 'Instead put the large files in cloud storage and use DEPS to\n' +
4178 'fetch them.\n' + '\n'.join(too_large_files))
4179 return [
4180 output_api.PresubmitError('Too large files found in commit',
4181 long_text=message + '\n')
4182 ]
4183 else:
4184 return []
Daniel Bratell93eb6c62019-04-29 20:13:364185
Max Morozb47503b2019-08-08 21:03:274186
Saagar Sanghavifceeaae2020-08-12 16:40:364187def CheckFuzzTargetsOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504188 """Checks specific for fuzz target sources."""
4189 EXPORTED_SYMBOLS = [
4190 'LLVMFuzzerInitialize',
4191 'LLVMFuzzerCustomMutator',
4192 'LLVMFuzzerCustomCrossOver',
4193 'LLVMFuzzerMutate',
4194 ]
Max Morozb47503b2019-08-08 21:03:274195
Sam Maiera6e76d72022-02-11 21:43:504196 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
Max Morozb47503b2019-08-08 21:03:274197
Sam Maiera6e76d72022-02-11 21:43:504198 def FilterFile(affected_file):
4199 """Ignore libFuzzer source code."""
4200 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4201 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274202
Sam Maiera6e76d72022-02-11 21:43:504203 return input_api.FilterSourceFile(affected_file,
4204 files_to_check=[files_to_check],
4205 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274206
Sam Maiera6e76d72022-02-11 21:43:504207 files_with_missing_header = []
4208 for f in input_api.AffectedSourceFiles(FilterFile):
4209 contents = input_api.ReadFile(f, 'r')
4210 if REQUIRED_HEADER in contents:
4211 continue
Max Morozb47503b2019-08-08 21:03:274212
Sam Maiera6e76d72022-02-11 21:43:504213 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4214 files_with_missing_header.append(f.LocalPath())
Max Morozb47503b2019-08-08 21:03:274215
Sam Maiera6e76d72022-02-11 21:43:504216 if not files_with_missing_header:
4217 return []
Max Morozb47503b2019-08-08 21:03:274218
Sam Maiera6e76d72022-02-11 21:43:504219 long_text = (
4220 'If you define any of the libFuzzer optional functions (%s), it is '
4221 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4222 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4223 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4224 'to access command line arguments passed to the fuzzer. Instead, prefer '
4225 'static initialization and shared resources as documented in '
4226 'https://chromium.googlesource.com/chromium/src/+/main/testing/'
4227 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n'
4228 % (', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER))
Max Morozb47503b2019-08-08 21:03:274229
Sam Maiera6e76d72022-02-11 21:43:504230 return [
4231 output_api.PresubmitPromptWarning(message="Missing '%s' in:" %
4232 REQUIRED_HEADER,
4233 items=files_with_missing_header,
4234 long_text=long_text)
4235 ]
Max Morozb47503b2019-08-08 21:03:274236
4237
Mohamed Heikald048240a2019-11-12 16:57:374238def _CheckNewImagesWarning(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504239 """
4240 Warns authors who add images into the repo to make sure their images are
4241 optimized before committing.
4242 """
4243 images_added = False
4244 image_paths = []
4245 errors = []
4246 filter_lambda = lambda x: input_api.FilterSourceFile(
4247 x,
4248 files_to_skip=(('(?i).*test', r'.*\/junit\/') + input_api.
4249 DEFAULT_FILES_TO_SKIP),
4250 files_to_check=[r'.*\/(drawable|mipmap)'])
4251 for f in input_api.AffectedFiles(include_deletes=False,
4252 file_filter=filter_lambda):
4253 local_path = f.LocalPath().lower()
4254 if any(
4255 local_path.endswith(extension)
4256 for extension in _IMAGE_EXTENSIONS):
4257 images_added = True
4258 image_paths.append(f)
4259 if images_added:
4260 errors.append(
4261 output_api.PresubmitPromptWarning(
4262 'It looks like you are trying to commit some images. If these are '
4263 'non-test-only images, please make sure to read and apply the tips in '
4264 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4265 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4266 'FYI only and will not block your CL on the CQ.', image_paths))
4267 return errors
Mohamed Heikald048240a2019-11-12 16:57:374268
4269
Saagar Sanghavifceeaae2020-08-12 16:40:364270def ChecksAndroidSpecificOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504271 """Groups upload checks that target android code."""
4272 results = []
4273 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
4274 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
4275 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
4276 results.extend(_CheckAndroidToastUsage(input_api, output_api))
4277 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4278 results.extend(_CheckAndroidTestJUnitFrameworkImport(
4279 input_api, output_api))
4280 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
4281 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
4282 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
4283 results.extend(_CheckNewImagesWarning(input_api, output_api))
4284 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
4285 results.extend(_CheckAndroidInfoBarDeprecation(input_api, output_api))
4286 return results
4287
Becky Zhou7c69b50992018-12-10 19:37:574288
Saagar Sanghavifceeaae2020-08-12 16:40:364289def ChecksAndroidSpecificOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504290 """Groups commit checks that target android code."""
4291 results = []
4292 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
4293 return results
dgnaa68d5e2015-06-10 10:08:224294
Chris Hall59f8d0c72020-05-01 07:31:194295# TODO(chrishall): could we additionally match on any path owned by
4296# ui/accessibility/OWNERS ?
4297_ACCESSIBILITY_PATHS = (
4298 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4299 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4300 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4301 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4302 r"^content[\\/]browser[\\/]accessibility[\\/]",
4303 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4304 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4305 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4306 r"^ui[\\/]accessibility[\\/]",
4307 r"^ui[\\/]views[\\/]accessibility[\\/]",
4308)
4309
Saagar Sanghavifceeaae2020-08-12 16:40:364310def CheckAccessibilityRelnotesField(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504311 """Checks that commits to accessibility code contain an AX-Relnotes field in
4312 their commit message."""
Chris Hall59f8d0c72020-05-01 07:31:194313
Sam Maiera6e76d72022-02-11 21:43:504314 def FileFilter(affected_file):
4315 paths = _ACCESSIBILITY_PATHS
4316 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194317
Sam Maiera6e76d72022-02-11 21:43:504318 # Only consider changes affecting accessibility paths.
4319 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4320 return []
Akihiro Ota08108e542020-05-20 15:30:534321
Sam Maiera6e76d72022-02-11 21:43:504322 # AX-Relnotes can appear in either the description or the footer.
4323 # When searching the description, require 'AX-Relnotes:' to appear at the
4324 # beginning of a line.
4325 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4326 description_has_relnotes = any(
4327 ax_regex.match(line)
4328 for line in input_api.change.DescriptionText().lower().splitlines())
Chris Hall59f8d0c72020-05-01 07:31:194329
Sam Maiera6e76d72022-02-11 21:43:504330 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4331 'AX-Relnotes', [])
4332 if description_has_relnotes or footer_relnotes:
4333 return []
Chris Hall59f8d0c72020-05-01 07:31:194334
Sam Maiera6e76d72022-02-11 21:43:504335 # TODO(chrishall): link to Relnotes documentation in message.
4336 message = (
4337 "Missing 'AX-Relnotes:' field required for accessibility changes"
4338 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4339 "user-facing changes"
4340 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4341 "user-facing effects"
4342 "\n if this is confusing or annoying then please contact members "
4343 "of ui/accessibility/OWNERS.")
4344
4345 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224346
Mark Schillacie5a0be22022-01-19 00:38:394347
4348_ACCESSIBILITY_EVENTS_TEST_PATH = (
4349 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]event[\\/].*\.html",
4350)
4351
4352_ACCESSIBILITY_TREE_TEST_PATH = (
4353 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]accname[\\/].*\.html",
4354 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]aria[\\/].*\.html",
4355 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]css[\\/].*\.html",
4356 r"^content[\\/]test[\\/]data[\\/]accessibility[\\/]html[\\/].*\.html",
4357)
4358
4359_ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH = (
4360 r"^.*[\\/]WebContentsAccessibilityEventsTest\.java",
4361)
4362
4363_ACCESSIBILITY_ANDROID_TREE_TEST_PATH = (
Mark Schillaci6f568a52022-02-17 18:41:444364 r"^.*[\\/]WebContentsAccessibilityTreeTest\.java",
Mark Schillacie5a0be22022-01-19 00:38:394365)
4366
4367def CheckAccessibilityEventsTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504368 """Checks that commits that include a newly added, renamed/moved, or deleted
4369 test in the DumpAccessibilityEventsTest suite also includes a corresponding
4370 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394371
Sam Maiera6e76d72022-02-11 21:43:504372 def FilePathFilter(affected_file):
4373 paths = _ACCESSIBILITY_EVENTS_TEST_PATH
4374 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394375
Sam Maiera6e76d72022-02-11 21:43:504376 def AndroidFilePathFilter(affected_file):
4377 paths = _ACCESSIBILITY_ANDROID_EVENTS_TEST_PATH
4378 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394379
Sam Maiera6e76d72022-02-11 21:43:504380 # Only consider changes in the events test data path with html type.
4381 if not any(
4382 input_api.AffectedFiles(include_deletes=True,
4383 file_filter=FilePathFilter)):
4384 return []
Mark Schillacie5a0be22022-01-19 00:38:394385
Sam Maiera6e76d72022-02-11 21:43:504386 # If the commit contains any change to the Android test file, ignore.
4387 if any(
4388 input_api.AffectedFiles(include_deletes=True,
4389 file_filter=AndroidFilePathFilter)):
4390 return []
Mark Schillacie5a0be22022-01-19 00:38:394391
Sam Maiera6e76d72022-02-11 21:43:504392 # Only consider changes that are adding/renaming or deleting a file
4393 message = []
4394 for f in input_api.AffectedFiles(include_deletes=True,
4395 file_filter=FilePathFilter):
4396 if f.Action() == 'A' or f.Action() == 'D':
4397 message = (
4398 "It appears that you are adding, renaming or deleting"
4399 "\na dump_accessibility_events* test, but have not included"
4400 "\na corresponding change for Android."
4401 "\nPlease include (or remove) the test from:"
4402 "\n content/public/android/javatests/src/org/chromium/"
4403 "content/browser/accessibility/"
4404 "WebContentsAccessibilityEventsTest.java"
4405 "\nIf this message is confusing or annoying, please contact"
4406 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394407
Sam Maiera6e76d72022-02-11 21:43:504408 # If no message was set, return empty.
4409 if not len(message):
4410 return []
4411
4412 return [output_api.PresubmitPromptWarning(message)]
4413
Mark Schillacie5a0be22022-01-19 00:38:394414
4415def CheckAccessibilityTreeTestsAreIncludedForAndroid(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504416 """Checks that commits that include a newly added, renamed/moved, or deleted
4417 test in the DumpAccessibilityTreeTest suite also includes a corresponding
4418 change to the Android test."""
Mark Schillacie5a0be22022-01-19 00:38:394419
Sam Maiera6e76d72022-02-11 21:43:504420 def FilePathFilter(affected_file):
4421 paths = _ACCESSIBILITY_TREE_TEST_PATH
4422 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394423
Sam Maiera6e76d72022-02-11 21:43:504424 def AndroidFilePathFilter(affected_file):
4425 paths = _ACCESSIBILITY_ANDROID_TREE_TEST_PATH
4426 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Mark Schillacie5a0be22022-01-19 00:38:394427
Sam Maiera6e76d72022-02-11 21:43:504428 # Only consider changes in the various tree test data paths with html type.
4429 if not any(
4430 input_api.AffectedFiles(include_deletes=True,
4431 file_filter=FilePathFilter)):
4432 return []
Mark Schillacie5a0be22022-01-19 00:38:394433
Sam Maiera6e76d72022-02-11 21:43:504434 # If the commit contains any change to the Android test file, ignore.
4435 if any(
4436 input_api.AffectedFiles(include_deletes=True,
4437 file_filter=AndroidFilePathFilter)):
4438 return []
Mark Schillacie5a0be22022-01-19 00:38:394439
Sam Maiera6e76d72022-02-11 21:43:504440 # Only consider changes that are adding/renaming or deleting a file
4441 message = []
4442 for f in input_api.AffectedFiles(include_deletes=True,
4443 file_filter=FilePathFilter):
4444 if f.Action() == 'A' or f.Action() == 'D':
4445 message = (
4446 "It appears that you are adding, renaming or deleting"
4447 "\na dump_accessibility_tree* test, but have not included"
4448 "\na corresponding change for Android."
4449 "\nPlease include (or remove) the test from:"
4450 "\n content/public/android/javatests/src/org/chromium/"
4451 "content/browser/accessibility/"
4452 "WebContentsAccessibilityTreeTest.java"
4453 "\nIf this message is confusing or annoying, please contact"
4454 "\nmembers of ui/accessibility/OWNERS.")
Mark Schillacie5a0be22022-01-19 00:38:394455
Sam Maiera6e76d72022-02-11 21:43:504456 # If no message was set, return empty.
4457 if not len(message):
4458 return []
4459
4460 return [output_api.PresubmitPromptWarning(message)]
Mark Schillacie5a0be22022-01-19 00:38:394461
4462
seanmccullough4a9356252021-04-08 19:54:094463# string pattern, sequence of strings to show when pattern matches,
4464# error flag. True if match is a presubmit error, otherwise it's a warning.
4465_NON_INCLUSIVE_TERMS = (
4466 (
4467 # Note that \b pattern in python re is pretty particular. In this
4468 # regexp, 'class WhiteList ...' will match, but 'class FooWhiteList
4469 # ...' will not. This may require some tweaking to catch these cases
4470 # without triggering a lot of false positives. Leaving it naive and
4471 # less matchy for now.
seanmccullough56d1e3cf2021-12-03 18:18:324472 r'/\b(?i)((black|white)list|master|slave)\b', # nocheck
seanmccullough4a9356252021-04-08 19:54:094473 (
4474 'Please don\'t use blacklist, whitelist, ' # nocheck
4475 'or slave in your', # nocheck
4476 'code and make every effort to use other terms. Using "// nocheck"',
4477 '"# nocheck" or "<!-- nocheck -->"',
4478 'at the end of the offending line will bypass this PRESUBMIT error',
4479 'but avoid using this whenever possible. Reach out to',
4480 '[email protected] if you have questions'),
4481 True),)
4482
Saagar Sanghavifceeaae2020-08-12 16:40:364483def ChecksCommon(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504484 """Checks common to both upload and commit."""
4485 results = []
Eric Boren6fd2b932018-01-25 15:05:084486 results.extend(
Sam Maiera6e76d72022-02-11 21:43:504487 input_api.canned_checks.PanProjectChecks(
4488 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084489
Sam Maiera6e76d72022-02-11 21:43:504490 author = input_api.change.author_email
4491 if author and author not in _KNOWN_ROBOTS:
4492 results.extend(
4493 input_api.canned_checks.CheckAuthorizedAuthor(
4494 input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:244495
Sam Maiera6e76d72022-02-11 21:43:504496 results.extend(
4497 input_api.canned_checks.CheckChangeHasNoTabs(
4498 input_api,
4499 output_api,
4500 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
4501 results.extend(
4502 input_api.RunTests(
4503 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Edward Lesmesce51df52020-08-04 22:10:174504
Bruce Dawsonc8054482022-03-28 15:33:374505 dirmd = 'dirmd.bat' if input_api.is_windows else 'dirmd'
Sam Maiera6e76d72022-02-11 21:43:504506 dirmd_bin = input_api.os_path.join(input_api.PresubmitLocalPath(),
Bruce Dawsonc8054482022-03-28 15:33:374507 'third_party', 'depot_tools', dirmd)
Sam Maiera6e76d72022-02-11 21:43:504508 results.extend(
4509 input_api.RunTests(
4510 input_api.canned_checks.CheckDirMetadataFormat(
4511 input_api, output_api, dirmd_bin)))
4512 results.extend(
4513 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4514 input_api, output_api))
4515 results.extend(
4516 input_api.canned_checks.CheckNoNewMetadataInOwners(
4517 input_api, output_api))
4518 results.extend(
4519 input_api.canned_checks.CheckInclusiveLanguage(
4520 input_api,
4521 output_api,
4522 excluded_directories_relative_path=[
4523 'infra', 'inclusive_language_presubmit_exempt_dirs.txt'
4524 ],
4525 non_inclusive_terms=_NON_INCLUSIVE_TERMS))
Dirk Prankee3c9c62d2021-05-18 18:35:594526
Sam Maiera6e76d72022-02-11 21:43:504527 for f in input_api.AffectedFiles():
4528 path, name = input_api.os_path.split(f.LocalPath())
4529 if name == 'PRESUBMIT.py':
4530 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
4531 path)
4532 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4533 if f.Action() != 'D' and input_api.os_path.exists(test_file):
4534 # The PRESUBMIT.py file (and the directory containing it) might
4535 # have been affected by being moved or removed, so only try to
4536 # run the tests if they still exist.
4537 use_python3 = False
4538 with open(f.LocalPath()) as fp:
4539 use_python3 = any(
4540 line.startswith('USE_PYTHON3 = True')
4541 for line in fp.readlines())
4542
4543 results.extend(
4544 input_api.canned_checks.RunUnitTestsInDirectory(
4545 input_api,
4546 output_api,
4547 full_path,
4548 files_to_check=[r'^PRESUBMIT_test\.py$'],
4549 run_on_python2=not use_python3,
4550 run_on_python3=use_python3,
4551 skip_shebang_check=True))
4552 return results
[email protected]1f7b4172010-01-28 01:17:344553
[email protected]b337cb5b2011-01-23 21:24:054554
Saagar Sanghavifceeaae2020-08-12 16:40:364555def CheckPatchFiles(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504556 problems = [
4557 f.LocalPath() for f in input_api.AffectedFiles()
4558 if f.LocalPath().endswith(('.orig', '.rej'))
4559 ]
4560 # Cargo.toml.orig files are part of third-party crates downloaded from
4561 # crates.io and should be included.
4562 problems = [f for f in problems if not f.endswith('Cargo.toml.orig')]
4563 if problems:
4564 return [
4565 output_api.PresubmitError("Don't commit .rej and .orig files.",
4566 problems)
4567 ]
4568 else:
4569 return []
[email protected]b8079ae4a2012-12-05 19:56:494570
4571
Saagar Sanghavifceeaae2020-08-12 16:40:364572def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504573 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4574 macro_re = input_api.re.compile(
4575 r'^\s*#(el)?if.*\bdefined\(((COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
4576 include_re = input_api.re.compile(r'^#include\s+"build/build_config.h"',
4577 input_api.re.MULTILINE)
4578 extension_re = input_api.re.compile(r'\.[a-z]+$')
4579 errors = []
4580 for f in input_api.AffectedFiles(include_deletes=False):
4581 if not f.LocalPath().endswith(
4582 ('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4583 continue
4584 found_line_number = None
4585 found_macro = None
4586 all_lines = input_api.ReadFile(f, 'r').splitlines()
4587 for line_num, line in enumerate(all_lines):
4588 match = macro_re.search(line)
4589 if match:
4590 found_line_number = line_num
4591 found_macro = match.group(2)
4592 break
4593 if not found_line_number:
4594 continue
Kent Tamura5a8755d2017-06-29 23:37:074595
Sam Maiera6e76d72022-02-11 21:43:504596 found_include_line = -1
4597 for line_num, line in enumerate(all_lines):
4598 if include_re.search(line):
4599 found_include_line = line_num
4600 break
4601 if found_include_line >= 0 and found_include_line < found_line_number:
4602 continue
Kent Tamura5a8755d2017-06-29 23:37:074603
Sam Maiera6e76d72022-02-11 21:43:504604 if not f.LocalPath().endswith('.h'):
4605 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4606 try:
4607 content = input_api.ReadFile(primary_header_path, 'r')
4608 if include_re.search(content):
4609 continue
4610 except IOError:
4611 pass
4612 errors.append('%s:%d %s macro is used without first including build/'
4613 'build_config.h.' %
4614 (f.LocalPath(), found_line_number, found_macro))
4615 if errors:
4616 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4617 return []
Kent Tamura5a8755d2017-06-29 23:37:074618
4619
Lei Zhang1c12a22f2021-05-12 11:28:454620def CheckForSuperfluousStlIncludesInHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504621 stl_include_re = input_api.re.compile(r'^#include\s+<('
4622 r'algorithm|'
4623 r'array|'
4624 r'limits|'
4625 r'list|'
4626 r'map|'
4627 r'memory|'
4628 r'queue|'
4629 r'set|'
4630 r'string|'
4631 r'unordered_map|'
4632 r'unordered_set|'
4633 r'utility|'
4634 r'vector)>')
4635 std_namespace_re = input_api.re.compile(r'std::')
4636 errors = []
4637 for f in input_api.AffectedFiles():
4638 if not _IsCPlusPlusHeaderFile(input_api, f.LocalPath()):
4639 continue
Lei Zhang1c12a22f2021-05-12 11:28:454640
Sam Maiera6e76d72022-02-11 21:43:504641 uses_std_namespace = False
4642 has_stl_include = False
4643 for line in f.NewContents():
4644 if has_stl_include and uses_std_namespace:
4645 break
Lei Zhang1c12a22f2021-05-12 11:28:454646
Sam Maiera6e76d72022-02-11 21:43:504647 if not has_stl_include and stl_include_re.search(line):
4648 has_stl_include = True
4649 continue
Lei Zhang1c12a22f2021-05-12 11:28:454650
Bruce Dawson4a5579a2022-04-08 17:11:364651 if not uses_std_namespace and (std_namespace_re.search(line)
4652 or 'no-std-usage-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504653 uses_std_namespace = True
4654 continue
Lei Zhang1c12a22f2021-05-12 11:28:454655
Sam Maiera6e76d72022-02-11 21:43:504656 if has_stl_include and not uses_std_namespace:
4657 errors.append(
4658 '%s: Includes STL header(s) but does not reference std::' %
4659 f.LocalPath())
4660 if errors:
4661 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4662 return []
Lei Zhang1c12a22f2021-05-12 11:28:454663
4664
Xiaohan Wang42d96c22022-01-20 17:23:114665def _CheckForDeprecatedOSMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504666 """Check for sensible looking, totally invalid OS macros."""
4667 preprocessor_statement = input_api.re.compile(r'^\s*#')
4668 os_macro = input_api.re.compile(r'defined\(OS_([^)]+)\)')
4669 results = []
4670 for lnum, line in f.ChangedContents():
4671 if preprocessor_statement.search(line):
4672 for match in os_macro.finditer(line):
4673 results.append(
4674 ' %s:%d: %s' %
4675 (f.LocalPath(), lnum, 'defined(OS_' + match.group(1) +
4676 ') -> BUILDFLAG(IS_' + match.group(1) + ')'))
4677 return results
[email protected]b00342e7f2013-03-26 16:21:544678
4679
Xiaohan Wang42d96c22022-01-20 17:23:114680def CheckForDeprecatedOSMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504681 """Check all affected files for invalid OS macros."""
4682 bad_macros = []
4683 for f in input_api.AffectedSourceFiles(None):
4684 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
4685 bad_macros.extend(_CheckForDeprecatedOSMacrosInFile(input_api, f))
[email protected]b00342e7f2013-03-26 16:21:544686
Sam Maiera6e76d72022-02-11 21:43:504687 if not bad_macros:
4688 return []
[email protected]b00342e7f2013-03-26 16:21:544689
Sam Maiera6e76d72022-02-11 21:43:504690 return [
4691 output_api.PresubmitError(
4692 'OS macros have been deprecated. Please use BUILDFLAGs instead (still '
4693 'defined in build_config.h):', bad_macros)
4694 ]
[email protected]b00342e7f2013-03-26 16:21:544695
lliabraa35bab3932014-10-01 12:16:444696
4697def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
Sam Maiera6e76d72022-02-11 21:43:504698 """Check all affected files for invalid "if defined" macros."""
4699 ALWAYS_DEFINED_MACROS = (
4700 "TARGET_CPU_PPC",
4701 "TARGET_CPU_PPC64",
4702 "TARGET_CPU_68K",
4703 "TARGET_CPU_X86",
4704 "TARGET_CPU_ARM",
4705 "TARGET_CPU_MIPS",
4706 "TARGET_CPU_SPARC",
4707 "TARGET_CPU_ALPHA",
4708 "TARGET_IPHONE_SIMULATOR",
4709 "TARGET_OS_EMBEDDED",
4710 "TARGET_OS_IPHONE",
4711 "TARGET_OS_MAC",
4712 "TARGET_OS_UNIX",
4713 "TARGET_OS_WIN32",
4714 )
4715 ifdef_macro = input_api.re.compile(
4716 r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4717 results = []
4718 for lnum, line in f.ChangedContents():
4719 for match in ifdef_macro.finditer(line):
4720 if match.group(1) in ALWAYS_DEFINED_MACROS:
4721 always_defined = ' %s is always defined. ' % match.group(1)
4722 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4723 results.append(
4724 ' %s:%d %s\n\t%s' %
4725 (f.LocalPath(), lnum, always_defined, did_you_mean))
4726 return results
lliabraa35bab3932014-10-01 12:16:444727
4728
Saagar Sanghavifceeaae2020-08-12 16:40:364729def CheckForInvalidIfDefinedMacros(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504730 """Check all affected files for invalid "if defined" macros."""
4731 bad_macros = []
4732 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
4733 for f in input_api.AffectedFiles():
4734 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
4735 continue
4736 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4737 bad_macros.extend(
4738 _CheckForInvalidIfDefinedMacrosInFile(input_api, f))
lliabraa35bab3932014-10-01 12:16:444739
Sam Maiera6e76d72022-02-11 21:43:504740 if not bad_macros:
4741 return []
lliabraa35bab3932014-10-01 12:16:444742
Sam Maiera6e76d72022-02-11 21:43:504743 return [
4744 output_api.PresubmitError(
4745 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4746 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4747 bad_macros)
4748 ]
lliabraa35bab3932014-10-01 12:16:444749
4750
Saagar Sanghavifceeaae2020-08-12 16:40:364751def CheckForIPCRules(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504752 """Check for same IPC rules described in
4753 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4754 """
4755 base_pattern = r'IPC_ENUM_TRAITS\('
4756 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4757 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
mlamouria82272622014-09-16 18:45:044758
Sam Maiera6e76d72022-02-11 21:43:504759 problems = []
4760 for f in input_api.AffectedSourceFiles(None):
4761 local_path = f.LocalPath()
4762 if not local_path.endswith('.h'):
4763 continue
4764 for line_number, line in f.ChangedContents():
4765 if inclusion_pattern.search(
4766 line) and not comment_pattern.search(line):
4767 problems.append('%s:%d\n %s' %
4768 (local_path, line_number, line.strip()))
mlamouria82272622014-09-16 18:45:044769
Sam Maiera6e76d72022-02-11 21:43:504770 if problems:
4771 return [
4772 output_api.PresubmitPromptWarning(_IPC_ENUM_TRAITS_DEPRECATED,
4773 problems)
4774 ]
4775 else:
4776 return []
mlamouria82272622014-09-16 18:45:044777
[email protected]b00342e7f2013-03-26 16:21:544778
Saagar Sanghavifceeaae2020-08-12 16:40:364779def CheckForLongPathnames(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504780 """Check to make sure no files being submitted have long paths.
4781 This causes issues on Windows.
4782 """
4783 problems = []
4784 for f in input_api.AffectedTestableFiles():
4785 local_path = f.LocalPath()
4786 # Windows has a path limit of 260 characters. Limit path length to 200 so
4787 # that we have some extra for the prefix on dev machines and the bots.
4788 if len(local_path) > 200:
4789 problems.append(local_path)
Stephen Martinis97a394142018-06-07 23:06:054790
Sam Maiera6e76d72022-02-11 21:43:504791 if problems:
4792 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4793 else:
4794 return []
Stephen Martinis97a394142018-06-07 23:06:054795
4796
Saagar Sanghavifceeaae2020-08-12 16:40:364797def CheckForIncludeGuards(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504798 """Check that header files have proper guards against multiple inclusion.
4799 If a file should not have such guards (and it probably should) then it
Bruce Dawson4a5579a2022-04-08 17:11:364800 should include the string "no-include-guard-because-multiply-included" or
4801 "no-include-guard-because-pch-file".
Sam Maiera6e76d72022-02-11 21:43:504802 """
Daniel Bratell8ba52722018-03-02 16:06:144803
Sam Maiera6e76d72022-02-11 21:43:504804 def is_chromium_header_file(f):
4805 # We only check header files under the control of the Chromium
4806 # project. That is, those outside third_party apart from
4807 # third_party/blink.
4808 # We also exclude *_message_generator.h headers as they use
4809 # include guards in a special, non-typical way.
4810 file_with_path = input_api.os_path.normpath(f.LocalPath())
4811 return (file_with_path.endswith('.h')
4812 and not file_with_path.endswith('_message_generator.h')
Bruce Dawson4c4c2922022-05-02 18:07:334813 and not file_with_path.endswith('com_imported_mstscax.h')
Sam Maiera6e76d72022-02-11 21:43:504814 and (not file_with_path.startswith('third_party')
4815 or file_with_path.startswith(
4816 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144817
Sam Maiera6e76d72022-02-11 21:43:504818 def replace_special_with_underscore(string):
4819 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144820
Sam Maiera6e76d72022-02-11 21:43:504821 errors = []
Daniel Bratell8ba52722018-03-02 16:06:144822
Sam Maiera6e76d72022-02-11 21:43:504823 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
4824 guard_name = None
4825 guard_line_number = None
4826 seen_guard_end = False
Daniel Bratell8ba52722018-03-02 16:06:144827
Sam Maiera6e76d72022-02-11 21:43:504828 file_with_path = input_api.os_path.normpath(f.LocalPath())
4829 base_file_name = input_api.os_path.splitext(
4830 input_api.os_path.basename(file_with_path))[0]
4831 upper_base_file_name = base_file_name.upper()
Daniel Bratell8ba52722018-03-02 16:06:144832
Sam Maiera6e76d72022-02-11 21:43:504833 expected_guard = replace_special_with_underscore(
4834 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144835
Sam Maiera6e76d72022-02-11 21:43:504836 # For "path/elem/file_name.h" we should really only accept
4837 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4838 # are too many (1000+) files with slight deviations from the
4839 # coding style. The most important part is that the include guard
4840 # is there, and that it's unique, not the name so this check is
4841 # forgiving for existing files.
4842 #
4843 # As code becomes more uniform, this could be made stricter.
Daniel Bratell8ba52722018-03-02 16:06:144844
Sam Maiera6e76d72022-02-11 21:43:504845 guard_name_pattern_list = [
4846 # Anything with the right suffix (maybe with an extra _).
4847 r'\w+_H__?',
Daniel Bratell8ba52722018-03-02 16:06:144848
Sam Maiera6e76d72022-02-11 21:43:504849 # To cover include guards with old Blink style.
4850 r'\w+_h',
Daniel Bratell8ba52722018-03-02 16:06:144851
Sam Maiera6e76d72022-02-11 21:43:504852 # Anything including the uppercase name of the file.
4853 r'\w*' + input_api.re.escape(
4854 replace_special_with_underscore(upper_base_file_name)) +
4855 r'\w*',
4856 ]
4857 guard_name_pattern = '|'.join(guard_name_pattern_list)
4858 guard_pattern = input_api.re.compile(r'#ifndef\s+(' +
4859 guard_name_pattern + ')')
Daniel Bratell8ba52722018-03-02 16:06:144860
Sam Maiera6e76d72022-02-11 21:43:504861 for line_number, line in enumerate(f.NewContents()):
Bruce Dawson4a5579a2022-04-08 17:11:364862 if ('no-include-guard-because-multiply-included' in line
4863 or 'no-include-guard-because-pch-file' in line):
Sam Maiera6e76d72022-02-11 21:43:504864 guard_name = 'DUMMY' # To not trigger check outside the loop.
4865 break
Daniel Bratell8ba52722018-03-02 16:06:144866
Sam Maiera6e76d72022-02-11 21:43:504867 if guard_name is None:
4868 match = guard_pattern.match(line)
4869 if match:
4870 guard_name = match.group(1)
4871 guard_line_number = line_number
Daniel Bratell8ba52722018-03-02 16:06:144872
Sam Maiera6e76d72022-02-11 21:43:504873 # We allow existing files to use include guards whose names
4874 # don't match the chromium style guide, but new files should
4875 # get it right.
Bruce Dawson6cc154e2022-04-12 20:39:494876 if guard_name != expected_guard:
4877 if not f.OldContents():
Sam Maiera6e76d72022-02-11 21:43:504878 errors.append(
4879 output_api.PresubmitPromptWarning(
4880 'Header using the wrong include guard name %s'
4881 % guard_name, [
4882 '%s:%d' %
4883 (f.LocalPath(), line_number + 1)
4884 ], 'Expected: %r\nFound: %r' %
4885 (expected_guard, guard_name)))
4886 else:
4887 # The line after #ifndef should have a #define of the same name.
4888 if line_number == guard_line_number + 1:
4889 expected_line = '#define %s' % guard_name
4890 if line != expected_line:
4891 errors.append(
4892 output_api.PresubmitPromptWarning(
4893 'Missing "%s" for include guard' %
4894 expected_line,
4895 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4896 'Expected: %r\nGot: %r' %
4897 (expected_line, line)))
Daniel Bratell8ba52722018-03-02 16:06:144898
Sam Maiera6e76d72022-02-11 21:43:504899 if not seen_guard_end and line == '#endif // %s' % guard_name:
4900 seen_guard_end = True
4901 elif seen_guard_end:
4902 if line.strip() != '':
4903 errors.append(
4904 output_api.PresubmitPromptWarning(
4905 'Include guard %s not covering the whole file'
4906 % (guard_name), [f.LocalPath()]))
4907 break # Nothing else to check and enough to warn once.
Daniel Bratell8ba52722018-03-02 16:06:144908
Sam Maiera6e76d72022-02-11 21:43:504909 if guard_name is None:
4910 errors.append(
4911 output_api.PresubmitPromptWarning(
Bruce Dawson32114b62022-04-11 16:45:494912 'Missing include guard in %s\n'
Sam Maiera6e76d72022-02-11 21:43:504913 'Recommended name: %s\n'
4914 'This check can be disabled by having the string\n'
Bruce Dawson4a5579a2022-04-08 17:11:364915 '"no-include-guard-because-multiply-included" or\n'
4916 '"no-include-guard-because-pch-file" in the header.'
Sam Maiera6e76d72022-02-11 21:43:504917 % (f.LocalPath(), expected_guard)))
4918
4919 return errors
Daniel Bratell8ba52722018-03-02 16:06:144920
4921
Saagar Sanghavifceeaae2020-08-12 16:40:364922def CheckForWindowsLineEndings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504923 """Check source code and known ascii text files for Windows style line
4924 endings.
4925 """
Bruce Dawson5efbdc652022-04-11 19:29:514926 known_text_files = r'.*\.(txt|html|htm|py|gyp|gypi|gn|isolate|icon)$'
mostynbb639aca52015-01-07 20:31:234927
Sam Maiera6e76d72022-02-11 21:43:504928 file_inclusion_pattern = (known_text_files,
4929 r'.+%s' % _IMPLEMENTATION_EXTENSIONS,
4930 r'.+%s' % _HEADER_EXTENSIONS)
mostynbb639aca52015-01-07 20:31:234931
Sam Maiera6e76d72022-02-11 21:43:504932 problems = []
4933 source_file_filter = lambda f: input_api.FilterSourceFile(
4934 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
4935 for f in input_api.AffectedSourceFiles(source_file_filter):
Bruce Dawson5efbdc652022-04-11 19:29:514936 # Ignore test files that contain crlf intentionally.
4937 if f.LocalPath().endswith('crlf.txt'):
4938 continue
Sam Maiera6e76d72022-02-11 21:43:504939 include_file = False
4940 for line in input_api.ReadFile(f, 'r').splitlines(True):
4941 if line.endswith('\r\n'):
4942 include_file = True
4943 if include_file:
4944 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234945
Sam Maiera6e76d72022-02-11 21:43:504946 if problems:
4947 return [
4948 output_api.PresubmitPromptWarning(
4949 'Are you sure that you want '
4950 'these files to contain Windows style line endings?\n' +
4951 '\n'.join(problems))
4952 ]
mostynbb639aca52015-01-07 20:31:234953
Sam Maiera6e76d72022-02-11 21:43:504954 return []
4955
mostynbb639aca52015-01-07 20:31:234956
Evan Stade6cfc964c12021-05-18 20:21:164957def CheckIconFilesForLicenseHeaders(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504958 """Check that .icon files (which are fragments of C++) have license headers.
4959 """
Evan Stade6cfc964c12021-05-18 20:21:164960
Sam Maiera6e76d72022-02-11 21:43:504961 icon_files = (r'.*\.icon$', )
Evan Stade6cfc964c12021-05-18 20:21:164962
Sam Maiera6e76d72022-02-11 21:43:504963 icons = lambda x: input_api.FilterSourceFile(x, files_to_check=icon_files)
4964 return input_api.canned_checks.CheckLicense(input_api,
4965 output_api,
4966 source_file_filter=icons)
4967
Evan Stade6cfc964c12021-05-18 20:21:164968
Jose Magana2b456f22021-03-09 23:26:404969def CheckForUseOfChromeAppsDeprecations(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:504970 """Check source code for use of Chrome App technologies being
4971 deprecated.
4972 """
Jose Magana2b456f22021-03-09 23:26:404973
Sam Maiera6e76d72022-02-11 21:43:504974 def _CheckForDeprecatedTech(input_api,
4975 output_api,
4976 detection_list,
4977 files_to_check=None,
4978 files_to_skip=None):
Jose Magana2b456f22021-03-09 23:26:404979
Sam Maiera6e76d72022-02-11 21:43:504980 if (files_to_check or files_to_skip):
4981 source_file_filter = lambda f: input_api.FilterSourceFile(
4982 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
4983 else:
4984 source_file_filter = None
4985
4986 problems = []
4987
4988 for f in input_api.AffectedSourceFiles(source_file_filter):
4989 if f.Action() == 'D':
4990 continue
4991 for _, line in f.ChangedContents():
4992 if any(detect in line for detect in detection_list):
4993 problems.append(f.LocalPath())
4994
4995 return problems
4996
4997 # to avoid this presubmit script triggering warnings
4998 files_to_skip = ['PRESUBMIT.py', 'PRESUBMIT_test.py']
Jose Magana2b456f22021-03-09 23:26:404999
5000 problems = []
5001
Sam Maiera6e76d72022-02-11 21:43:505002 # NMF: any files with extensions .nmf or NMF
5003 _NMF_FILES = r'\.(nmf|NMF)$'
5004 problems += _CheckForDeprecatedTech(
5005 input_api,
5006 output_api,
5007 detection_list=[''], # any change to the file will trigger warning
5008 files_to_check=[r'.+%s' % _NMF_FILES])
Jose Magana2b456f22021-03-09 23:26:405009
Sam Maiera6e76d72022-02-11 21:43:505010 # MANIFEST: any manifest.json that in its diff includes "app":
5011 _MANIFEST_FILES = r'(manifest\.json)$'
5012 problems += _CheckForDeprecatedTech(
5013 input_api,
5014 output_api,
5015 detection_list=['"app":'],
5016 files_to_check=[r'.*%s' % _MANIFEST_FILES])
Jose Magana2b456f22021-03-09 23:26:405017
Sam Maiera6e76d72022-02-11 21:43:505018 # NaCl / PNaCl: any file that in its diff contains the strings in the list
5019 problems += _CheckForDeprecatedTech(
5020 input_api,
5021 output_api,
5022 detection_list=['config=nacl', 'enable-nacl', 'cpu=pnacl', 'nacl_io'],
5023 files_to_skip=files_to_skip + [r"^native_client_sdk[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405024
Sam Maiera6e76d72022-02-11 21:43:505025 # PPAPI: any C/C++ file that in its diff includes a ppappi library
5026 problems += _CheckForDeprecatedTech(
5027 input_api,
5028 output_api,
5029 detection_list=['#include "ppapi', '#include <ppapi'],
5030 files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,
5031 r'.+%s' % _IMPLEMENTATION_EXTENSIONS),
5032 files_to_skip=[r"^ppapi[\\/]"])
Jose Magana2b456f22021-03-09 23:26:405033
Sam Maiera6e76d72022-02-11 21:43:505034 if problems:
5035 return [
5036 output_api.PresubmitPromptWarning(
5037 'You are adding/modifying code'
5038 'related to technologies which will soon be deprecated (Chrome Apps, NaCl,'
5039 ' PNaCl, PPAPI). See this blog post for more details:\n'
5040 'https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html\n'
5041 'and this documentation for options to replace these technologies:\n'
5042 'https://developer.chrome.com/docs/apps/migration/\n' +
5043 '\n'.join(problems))
5044 ]
Jose Magana2b456f22021-03-09 23:26:405045
Sam Maiera6e76d72022-02-11 21:43:505046 return []
Jose Magana2b456f22021-03-09 23:26:405047
mostynbb639aca52015-01-07 20:31:235048
Saagar Sanghavifceeaae2020-08-12 16:40:365049def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
Sam Maiera6e76d72022-02-11 21:43:505050 """Checks that all source files use SYSLOG properly."""
5051 syslog_files = []
5052 for f in input_api.AffectedSourceFiles(src_file_filter):
5053 for line_number, line in f.ChangedContents():
5054 if 'SYSLOG' in line:
5055 syslog_files.append(f.LocalPath() + ':' + str(line_number))
pastarmovj032ba5bc2017-01-12 10:41:565056
Sam Maiera6e76d72022-02-11 21:43:505057 if syslog_files:
5058 return [
5059 output_api.PresubmitPromptWarning(
5060 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
5061 ' calls.\nFiles to check:\n',
5062 items=syslog_files)
5063 ]
5064 return []
pastarmovj89f7ee12016-09-20 14:58:135065
5066
[email protected]1f7b4172010-01-28 01:17:345067def CheckChangeOnUpload(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505068 if input_api.version < [2, 0, 0]:
5069 return [
5070 output_api.PresubmitError(
5071 "Your depot_tools is out of date. "
5072 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5073 "but your version is %d.%d.%d" % tuple(input_api.version))
5074 ]
5075 results = []
5076 results.extend(
5077 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5078 return results
[email protected]ca8d1982009-02-19 16:33:125079
5080
5081def CheckChangeOnCommit(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505082 if input_api.version < [2, 0, 0]:
5083 return [
5084 output_api.PresubmitError(
5085 "Your depot_tools is out of date. "
5086 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
5087 "but your version is %d.%d.%d" % tuple(input_api.version))
5088 ]
Saagar Sanghavifceeaae2020-08-12 16:40:365089
Sam Maiera6e76d72022-02-11 21:43:505090 results = []
5091 # Make sure the tree is 'open'.
5092 results.extend(
5093 input_api.canned_checks.CheckTreeIsOpen(
5094 input_api,
5095 output_api,
5096 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:275097
Sam Maiera6e76d72022-02-11 21:43:505098 results.extend(
5099 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
5100 results.extend(
5101 input_api.canned_checks.CheckChangeHasBugField(input_api, output_api))
5102 results.extend(
5103 input_api.canned_checks.CheckChangeHasNoUnwantedTags(
5104 input_api, output_api))
Sam Maiera6e76d72022-02-11 21:43:505105 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145106
5107
Saagar Sanghavifceeaae2020-08-12 16:40:365108def CheckStrings(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505109 """Check string ICU syntax validity and if translation screenshots exist."""
5110 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
5111 # footer is set to true.
5112 git_footers = input_api.change.GitFootersFromDescription()
5113 skip_screenshot_check_footer = [
5114 footer.lower() for footer in git_footers.get(
5115 u'Skip-Translation-Screenshots-Check', [])
5116 ]
5117 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:025118
Sam Maiera6e76d72022-02-11 21:43:505119 import os
5120 import re
5121 import sys
5122 from io import StringIO
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145123
Sam Maiera6e76d72022-02-11 21:43:505124 new_or_added_paths = set(f.LocalPath() for f in input_api.AffectedFiles()
5125 if (f.Action() == 'A' or f.Action() == 'M'))
5126 removed_paths = set(f.LocalPath()
5127 for f in input_api.AffectedFiles(include_deletes=True)
5128 if f.Action() == 'D')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145129
Sam Maiera6e76d72022-02-11 21:43:505130 affected_grds = [
5131 f for f in input_api.AffectedFiles()
5132 if f.LocalPath().endswith(('.grd', '.grdp'))
5133 ]
5134 affected_grds = [
5135 f for f in affected_grds if not 'testdata' in f.LocalPath()
5136 ]
5137 if not affected_grds:
5138 return []
meacer8c0d3832019-12-26 21:46:165139
Sam Maiera6e76d72022-02-11 21:43:505140 affected_png_paths = [
5141 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
5142 if (f.LocalPath().endswith('.png'))
5143 ]
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145144
Sam Maiera6e76d72022-02-11 21:43:505145 # Check for screenshots. Developers can upload screenshots using
5146 # tools/translation/upload_screenshots.py which finds and uploads
5147 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
5148 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
5149 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
5150 #
5151 # The logic here is as follows:
5152 #
5153 # - If the CL has a .png file under the screenshots directory for a grd
5154 # file, warn the developer. Actual images should never be checked into the
5155 # Chrome repo.
5156 #
5157 # - If the CL contains modified or new messages in grd files and doesn't
5158 # contain the corresponding .sha1 files, warn the developer to add images
5159 # and upload them via tools/translation/upload_screenshots.py.
5160 #
5161 # - If the CL contains modified or new messages in grd files and the
5162 # corresponding .sha1 files, everything looks good.
5163 #
5164 # - If the CL contains removed messages in grd files but the corresponding
5165 # .sha1 files aren't removed, warn the developer to remove them.
5166 unnecessary_screenshots = []
5167 missing_sha1 = []
5168 unnecessary_sha1_files = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145169
Sam Maiera6e76d72022-02-11 21:43:505170 # This checks verifies that the ICU syntax of messages this CL touched is
5171 # valid, and reports any found syntax errors.
5172 # Without this presubmit check, ICU syntax errors in Chromium strings can land
5173 # without developers being aware of them. Later on, such ICU syntax errors
5174 # break message extraction for translation, hence would block Chromium
5175 # translations until they are fixed.
5176 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145177
Sam Maiera6e76d72022-02-11 21:43:505178 def _CheckScreenshotAdded(screenshots_dir, message_id):
5179 sha1_path = input_api.os_path.join(screenshots_dir,
5180 message_id + '.png.sha1')
5181 if sha1_path not in new_or_added_paths:
5182 missing_sha1.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145183
Sam Maiera6e76d72022-02-11 21:43:505184 def _CheckScreenshotRemoved(screenshots_dir, message_id):
5185 sha1_path = input_api.os_path.join(screenshots_dir,
5186 message_id + '.png.sha1')
5187 if input_api.os_path.exists(
5188 sha1_path) and sha1_path not in removed_paths:
5189 unnecessary_sha1_files.append(sha1_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145190
Sam Maiera6e76d72022-02-11 21:43:505191 def _ValidateIcuSyntax(text, level, signatures):
5192 """Validates ICU syntax of a text string.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145193
Sam Maiera6e76d72022-02-11 21:43:505194 Check if text looks similar to ICU and checks for ICU syntax correctness
5195 in this case. Reports various issues with ICU syntax and values of
5196 variants. Supports checking of nested messages. Accumulate information of
5197 each ICU messages found in the text for further checking.
Rainhard Findlingfc31844c52020-05-15 09:58:265198
Sam Maiera6e76d72022-02-11 21:43:505199 Args:
5200 text: a string to check.
5201 level: a number of current nesting level.
5202 signatures: an accumulator, a list of tuple of (level, variable,
5203 kind, variants).
Rainhard Findlingfc31844c52020-05-15 09:58:265204
Sam Maiera6e76d72022-02-11 21:43:505205 Returns:
5206 None if a string is not ICU or no issue detected.
5207 A tuple of (message, start index, end index) if an issue detected.
5208 """
5209 valid_types = {
5210 'plural': (frozenset(
5211 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5212 'other']), frozenset(['=1', 'other'])),
5213 'selectordinal': (frozenset(
5214 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many',
5215 'other']), frozenset(['one', 'other'])),
5216 'select': (frozenset(), frozenset(['other'])),
5217 }
Rainhard Findlingfc31844c52020-05-15 09:58:265218
Sam Maiera6e76d72022-02-11 21:43:505219 # Check if the message looks like an attempt to use ICU
5220 # plural. If yes - check if its syntax strictly matches ICU format.
5221 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b',
5222 text)
5223 if not like:
5224 signatures.append((level, None, None, None))
5225 return
Rainhard Findlingfc31844c52020-05-15 09:58:265226
Sam Maiera6e76d72022-02-11 21:43:505227 # Check for valid prefix and suffix
5228 m = re.match(
5229 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
5230 r'(plural|selectordinal|select),\s*'
5231 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
5232 if not m:
5233 return (('This message looks like an ICU plural, '
5234 'but does not follow ICU syntax.'), like.start(),
5235 like.end())
5236 starting, variable, kind, variant_pairs = m.groups()
5237 variants, depth, last_pos = _ParseIcuVariants(variant_pairs,
5238 m.start(4))
5239 if depth:
5240 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
5241 len(text))
5242 first = text[0]
5243 ending = text[last_pos:]
5244 if not starting:
5245 return ('Invalid ICU format. No initial opening bracket',
5246 last_pos - 1, last_pos)
5247 if not ending or '}' not in ending:
5248 return ('Invalid ICU format. No final closing bracket',
5249 last_pos - 1, last_pos)
5250 elif first != '{':
5251 return ((
5252 'Invalid ICU format. Extra characters at the start of a complex '
5253 'message (go/icu-message-migration): "%s"') % starting, 0,
5254 len(starting))
5255 elif ending != '}':
5256 return ((
5257 'Invalid ICU format. Extra characters at the end of a complex '
5258 'message (go/icu-message-migration): "%s"') % ending,
5259 last_pos - 1, len(text) - 1)
5260 if kind not in valid_types:
5261 return (('Unknown ICU message type %s. '
5262 'Valid types are: plural, select, selectordinal') % kind,
5263 0, 0)
5264 known, required = valid_types[kind]
5265 defined_variants = set()
5266 for variant, variant_range, value, value_range in variants:
5267 start, end = variant_range
5268 if variant in defined_variants:
5269 return ('Variant "%s" is defined more than once' % variant,
5270 start, end)
5271 elif known and variant not in known:
5272 return ('Variant "%s" is not valid for %s message' %
5273 (variant, kind), start, end)
5274 defined_variants.add(variant)
5275 # Check for nested structure
5276 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5277 if res:
5278 return (res[0], res[1] + value_range[0] + 1,
5279 res[2] + value_range[0] + 1)
5280 missing = required - defined_variants
5281 if missing:
5282 return ('Required variants missing: %s' % ', '.join(missing), 0,
5283 len(text))
5284 signatures.append((level, variable, kind, defined_variants))
Rainhard Findlingfc31844c52020-05-15 09:58:265285
Sam Maiera6e76d72022-02-11 21:43:505286 def _ParseIcuVariants(text, offset=0):
5287 """Parse variants part of ICU complex message.
Rainhard Findlingfc31844c52020-05-15 09:58:265288
Sam Maiera6e76d72022-02-11 21:43:505289 Builds a tuple of variant names and values, as well as
5290 their offsets in the input string.
Rainhard Findlingfc31844c52020-05-15 09:58:265291
Sam Maiera6e76d72022-02-11 21:43:505292 Args:
5293 text: a string to parse
5294 offset: additional offset to add to positions in the text to get correct
5295 position in the complete ICU string.
Rainhard Findlingfc31844c52020-05-15 09:58:265296
Sam Maiera6e76d72022-02-11 21:43:505297 Returns:
5298 List of tuples, each tuple consist of four fields: variant name,
5299 variant name span (tuple of two integers), variant value, value
5300 span (tuple of two integers).
5301 """
5302 depth, start, end = 0, -1, -1
5303 variants = []
5304 key = None
5305 for idx, char in enumerate(text):
5306 if char == '{':
5307 if not depth:
5308 start = idx
5309 chunk = text[end + 1:start]
5310 key = chunk.strip()
5311 pos = offset + end + 1 + chunk.find(key)
5312 span = (pos, pos + len(key))
5313 depth += 1
5314 elif char == '}':
5315 if not depth:
5316 return variants, depth, offset + idx
5317 depth -= 1
5318 if not depth:
5319 end = idx
5320 variants.append((key, span, text[start:end + 1],
5321 (offset + start, offset + end + 1)))
5322 return variants, depth, offset + end + 1
Rainhard Findlingfc31844c52020-05-15 09:58:265323
Sam Maiera6e76d72022-02-11 21:43:505324 try:
5325 old_sys_path = sys.path
5326 sys.path = sys.path + [
5327 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5328 'translation')
5329 ]
5330 from helper import grd_helper
5331 finally:
5332 sys.path = old_sys_path
Rainhard Findlingfc31844c52020-05-15 09:58:265333
Sam Maiera6e76d72022-02-11 21:43:505334 for f in affected_grds:
5335 file_path = f.LocalPath()
5336 old_id_to_msg_map = {}
5337 new_id_to_msg_map = {}
5338 # Note that this code doesn't check if the file has been deleted. This is
5339 # OK because it only uses the old and new file contents and doesn't load
5340 # the file via its path.
5341 # It's also possible that a file's content refers to a renamed or deleted
5342 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5343 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5344 # .grdp files.
5345 if file_path.endswith('.grdp'):
5346 if f.OldContents():
5347 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5348 '\n'.join(f.OldContents()))
5349 if f.NewContents():
5350 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
5351 '\n'.join(f.NewContents()))
5352 else:
5353 file_dir = input_api.os_path.dirname(file_path) or '.'
5354 if f.OldContents():
5355 old_id_to_msg_map = grd_helper.GetGrdMessages(
5356 StringIO('\n'.join(f.OldContents())), file_dir)
5357 if f.NewContents():
5358 new_id_to_msg_map = grd_helper.GetGrdMessages(
5359 StringIO('\n'.join(f.NewContents())), file_dir)
Rainhard Findlingfc31844c52020-05-15 09:58:265360
Sam Maiera6e76d72022-02-11 21:43:505361 grd_name, ext = input_api.os_path.splitext(
5362 input_api.os_path.basename(file_path))
5363 screenshots_dir = input_api.os_path.join(
5364 input_api.os_path.dirname(file_path),
5365 grd_name + ext.replace('.', '_'))
Rainhard Findlingfc31844c52020-05-15 09:58:265366
Sam Maiera6e76d72022-02-11 21:43:505367 # Compute added, removed and modified message IDs.
5368 old_ids = set(old_id_to_msg_map)
5369 new_ids = set(new_id_to_msg_map)
5370 added_ids = new_ids - old_ids
5371 removed_ids = old_ids - new_ids
5372 modified_ids = set([])
5373 for key in old_ids.intersection(new_ids):
5374 if (old_id_to_msg_map[key].ContentsAsXml('', True) !=
5375 new_id_to_msg_map[key].ContentsAsXml('', True)):
5376 # The message content itself changed. Require an updated screenshot.
5377 modified_ids.add(key)
5378 elif old_id_to_msg_map[key].attrs['meaning'] != \
5379 new_id_to_msg_map[key].attrs['meaning']:
5380 # The message meaning changed. Ensure there is a screenshot for it.
5381 sha1_path = input_api.os_path.join(screenshots_dir,
5382 key + '.png.sha1')
5383 if sha1_path not in new_or_added_paths and not \
5384 input_api.os_path.exists(sha1_path):
5385 # There is neither a previous screenshot nor is a new one added now.
5386 # Require a screenshot.
5387 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145388
Sam Maiera6e76d72022-02-11 21:43:505389 if run_screenshot_check:
5390 # Check the screenshot directory for .png files. Warn if there is any.
5391 for png_path in affected_png_paths:
5392 if png_path.startswith(screenshots_dir):
5393 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145394
Sam Maiera6e76d72022-02-11 21:43:505395 for added_id in added_ids:
5396 _CheckScreenshotAdded(screenshots_dir, added_id)
Rainhard Findlingd8d04372020-08-13 13:30:095397
Sam Maiera6e76d72022-02-11 21:43:505398 for modified_id in modified_ids:
5399 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145400
Sam Maiera6e76d72022-02-11 21:43:505401 for removed_id in removed_ids:
5402 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5403
5404 # Check new and changed strings for ICU syntax errors.
5405 for key in added_ids.union(modified_ids):
5406 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5407 err = _ValidateIcuSyntax(msg, 0, [])
5408 if err is not None:
5409 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
5410
5411 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265412 if run_screenshot_check:
Sam Maiera6e76d72022-02-11 21:43:505413 if unnecessary_screenshots:
5414 results.append(
5415 output_api.PresubmitError(
5416 'Do not include actual screenshots in the changelist. Run '
5417 'tools/translate/upload_screenshots.py to upload them instead:',
5418 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145419
Sam Maiera6e76d72022-02-11 21:43:505420 if missing_sha1:
5421 results.append(
5422 output_api.PresubmitError(
5423 'You are adding or modifying UI strings.\n'
5424 'To ensure the best translations, take screenshots of the relevant UI '
5425 '(https://g.co/chrome/translation) and add these files to your '
5426 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145427
Sam Maiera6e76d72022-02-11 21:43:505428 if unnecessary_sha1_files:
5429 results.append(
5430 output_api.PresubmitError(
5431 'You removed strings associated with these files. Remove:',
5432 sorted(unnecessary_sha1_files)))
5433 else:
5434 results.append(
5435 output_api.PresubmitPromptOrNotify('Skipping translation '
5436 'screenshots check.'))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145437
Sam Maiera6e76d72022-02-11 21:43:505438 if icu_syntax_errors:
5439 results.append(
5440 output_api.PresubmitPromptWarning(
5441 'ICU syntax errors were found in the following strings (problems or '
5442 'feedback? Contact [email protected]):',
5443 items=icu_syntax_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:265444
Sam Maiera6e76d72022-02-11 21:43:505445 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125446
5447
Saagar Sanghavifceeaae2020-08-12 16:40:365448def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125449 repo_root=None,
5450 translation_expectations_path=None,
5451 grd_files=None):
Sam Maiera6e76d72022-02-11 21:43:505452 import sys
5453 affected_grds = [
5454 f for f in input_api.AffectedFiles()
5455 if (f.LocalPath().endswith('.grd') or f.LocalPath().endswith('.grdp'))
5456 ]
5457 if not affected_grds:
5458 return []
5459
5460 try:
5461 old_sys_path = sys.path
5462 sys.path = sys.path + [
5463 input_api.os_path.join(input_api.PresubmitLocalPath(), 'tools',
5464 'translation')
5465 ]
5466 from helper import git_helper
5467 from helper import translation_helper
5468 finally:
5469 sys.path = old_sys_path
5470
5471 # Check that translation expectations can be parsed and we can get a list of
5472 # translatable grd files. |repo_root| and |translation_expectations_path| are
5473 # only passed by tests.
5474 if not repo_root:
5475 repo_root = input_api.PresubmitLocalPath()
5476 if not translation_expectations_path:
5477 translation_expectations_path = input_api.os_path.join(
5478 repo_root, 'tools', 'gritsettings', 'translation_expectations.pyl')
5479 if not grd_files:
5480 grd_files = git_helper.list_grds_in_repository(repo_root)
5481
5482 # Ignore bogus grd files used only for testing
5483 # ui/webui/resoucres/tools/generate_grd.py.
5484 ignore_path = input_api.os_path.join('ui', 'webui', 'resources', 'tools',
5485 'tests')
5486 grd_files = [p for p in grd_files if ignore_path not in p]
5487
5488 try:
5489 translation_helper.get_translatable_grds(
5490 repo_root, grd_files, translation_expectations_path)
5491 except Exception as e:
5492 return [
5493 output_api.PresubmitNotifyResult(
5494 'Failed to get a list of translatable grd files. This happens when:\n'
5495 ' - One of the modified grd or grdp files cannot be parsed or\n'
5496 ' - %s is not updated.\n'
5497 'Stack:\n%s' % (translation_expectations_path, str(e)))
5498 ]
Mustafa Emre Acer51f2f742020-03-09 19:41:125499 return []
5500
Ken Rockotc31f4832020-05-29 18:58:515501
Saagar Sanghavifceeaae2020-08-12 16:40:365502def CheckStableMojomChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505503 """Changes to [Stable] mojom types must preserve backward-compatibility."""
5504 changed_mojoms = input_api.AffectedFiles(
5505 include_deletes=True,
5506 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Erik Staabc734cd7a2021-11-23 03:11:525507
Sam Maiera6e76d72022-02-11 21:43:505508 if not changed_mojoms:
5509 return []
5510
5511 delta = []
5512 for mojom in changed_mojoms:
Sam Maiera6e76d72022-02-11 21:43:505513 delta.append({
5514 'filename': mojom.LocalPath(),
5515 'old': '\n'.join(mojom.OldContents()) or None,
5516 'new': '\n'.join(mojom.NewContents()) or None,
5517 })
5518
5519 process = input_api.subprocess.Popen([
Takuto Ikutadca10222022-04-13 02:51:215520 input_api.python3_executable,
Sam Maiera6e76d72022-02-11 21:43:505521 input_api.os_path.join(
5522 input_api.PresubmitLocalPath(), 'mojo', 'public', 'tools', 'mojom',
5523 'check_stable_mojom_compatibility.py'), '--src-root',
5524 input_api.PresubmitLocalPath()
5525 ],
5526 stdin=input_api.subprocess.PIPE,
5527 stdout=input_api.subprocess.PIPE,
5528 stderr=input_api.subprocess.PIPE,
5529 universal_newlines=True)
5530 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5531 if process.returncode:
5532 return [
5533 output_api.PresubmitError(
5534 'One or more [Stable] mojom definitions appears to have been changed '
5535 'in a way that is not backward-compatible.',
5536 long_text=error)
5537 ]
Erik Staabc734cd7a2021-11-23 03:11:525538 return []
5539
Dominic Battre645d42342020-12-04 16:14:105540def CheckDeprecationOfPreferences(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505541 """Removing a preference should come with a deprecation."""
Dominic Battre645d42342020-12-04 16:14:105542
Sam Maiera6e76d72022-02-11 21:43:505543 def FilterFile(affected_file):
5544 """Accept only .cc files and the like."""
5545 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
5546 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5547 input_api.DEFAULT_FILES_TO_SKIP)
5548 return input_api.FilterSourceFile(
5549 affected_file,
5550 files_to_check=file_inclusion_pattern,
5551 files_to_skip=files_to_skip)
Dominic Battre645d42342020-12-04 16:14:105552
Sam Maiera6e76d72022-02-11 21:43:505553 def ModifiedLines(affected_file):
5554 """Returns a list of tuples (line number, line text) of added and removed
5555 lines.
Dominic Battre645d42342020-12-04 16:14:105556
Sam Maiera6e76d72022-02-11 21:43:505557 Deleted lines share the same line number as the previous line.
Dominic Battre645d42342020-12-04 16:14:105558
Sam Maiera6e76d72022-02-11 21:43:505559 This relies on the scm diff output describing each changed code section
5560 with a line of the form
Dominic Battre645d42342020-12-04 16:14:105561
Sam Maiera6e76d72022-02-11 21:43:505562 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
5563 """
5564 line_num = 0
5565 modified_lines = []
5566 for line in affected_file.GenerateScmDiff().splitlines():
5567 # Extract <new line num> of the patch fragment (see format above).
5568 m = input_api.re.match(r'^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@',
5569 line)
5570 if m:
5571 line_num = int(m.groups(1)[0])
5572 continue
5573 if ((line.startswith('+') and not line.startswith('++'))
5574 or (line.startswith('-') and not line.startswith('--'))):
5575 modified_lines.append((line_num, line))
Dominic Battre645d42342020-12-04 16:14:105576
Sam Maiera6e76d72022-02-11 21:43:505577 if not line.startswith('-'):
5578 line_num += 1
5579 return modified_lines
Dominic Battre645d42342020-12-04 16:14:105580
Sam Maiera6e76d72022-02-11 21:43:505581 def FindLineWith(lines, needle):
5582 """Returns the line number (i.e. index + 1) in `lines` containing `needle`.
Dominic Battre645d42342020-12-04 16:14:105583
Sam Maiera6e76d72022-02-11 21:43:505584 If 0 or >1 lines contain `needle`, -1 is returned.
5585 """
5586 matching_line_numbers = [
5587 # + 1 for 1-based counting of line numbers.
5588 i + 1 for i, line in enumerate(lines) if needle in line
5589 ]
5590 return matching_line_numbers[0] if len(
5591 matching_line_numbers) == 1 else -1
Dominic Battre645d42342020-12-04 16:14:105592
Sam Maiera6e76d72022-02-11 21:43:505593 def ModifiedPrefMigration(affected_file):
5594 """Returns whether the MigrateObsolete.*Pref functions were modified."""
5595 # Determine first and last lines of MigrateObsolete.*Pref functions.
5596 new_contents = affected_file.NewContents()
5597 range_1 = (FindLineWith(new_contents,
5598 'BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'),
5599 FindLineWith(new_contents,
5600 'END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'))
5601 range_2 = (FindLineWith(new_contents,
5602 'BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS'),
5603 FindLineWith(new_contents,
5604 'END_MIGRATE_OBSOLETE_PROFILE_PREFS'))
5605 if (-1 in range_1 + range_2):
5606 raise Exception(
5607 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.'
5608 )
Dominic Battre645d42342020-12-04 16:14:105609
Sam Maiera6e76d72022-02-11 21:43:505610 # Check whether any of the modified lines are part of the
5611 # MigrateObsolete.*Pref functions.
5612 for line_nr, line in ModifiedLines(affected_file):
5613 if (range_1[0] <= line_nr <= range_1[1]
5614 or range_2[0] <= line_nr <= range_2[1]):
5615 return True
5616 return False
Dominic Battre645d42342020-12-04 16:14:105617
Sam Maiera6e76d72022-02-11 21:43:505618 register_pref_pattern = input_api.re.compile(r'Register.+Pref')
5619 browser_prefs_file_pattern = input_api.re.compile(
5620 r'chrome/browser/prefs/browser_prefs.cc')
Dominic Battre645d42342020-12-04 16:14:105621
Sam Maiera6e76d72022-02-11 21:43:505622 changes = input_api.AffectedFiles(include_deletes=True,
5623 file_filter=FilterFile)
5624 potential_problems = []
5625 for f in changes:
5626 for line in f.GenerateScmDiff().splitlines():
5627 # Check deleted lines for pref registrations.
5628 if (line.startswith('-') and not line.startswith('--')
5629 and register_pref_pattern.search(line)):
5630 potential_problems.append('%s: %s' % (f.LocalPath(), line))
Dominic Battre645d42342020-12-04 16:14:105631
Sam Maiera6e76d72022-02-11 21:43:505632 if browser_prefs_file_pattern.search(f.LocalPath()):
5633 # If the developer modified the MigrateObsolete.*Prefs() functions, we
5634 # assume that they knew that they have to deprecate preferences and don't
5635 # warn.
5636 try:
5637 if ModifiedPrefMigration(f):
5638 return []
5639 except Exception as e:
5640 return [output_api.PresubmitError(str(e))]
Dominic Battre645d42342020-12-04 16:14:105641
Sam Maiera6e76d72022-02-11 21:43:505642 if potential_problems:
5643 return [
5644 output_api.PresubmitPromptWarning(
5645 'Discovered possible removal of preference registrations.\n\n'
5646 'Please make sure to properly deprecate preferences by clearing their\n'
5647 'value for a couple of milestones before finally removing the code.\n'
5648 'Otherwise data may stay in the preferences files forever. See\n'
5649 'Migrate*Prefs() in chrome/browser/prefs/browser_prefs.cc and\n'
5650 'chrome/browser/prefs/README.md for examples.\n'
5651 'This may be a false positive warning (e.g. if you move preference\n'
5652 'registrations to a different place).\n', potential_problems)
5653 ]
5654 return []
5655
Matt Stark6ef08872021-07-29 01:21:465656
5657def CheckConsistentGrdChanges(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505658 """Changes to GRD files must be consistent for tools to read them."""
5659 changed_grds = input_api.AffectedFiles(
5660 include_deletes=False,
5661 file_filter=lambda f: f.LocalPath().endswith(('.grd')))
5662 errors = []
5663 invalid_file_regexes = [(input_api.re.compile(matcher), msg)
5664 for matcher, msg in _INVALID_GRD_FILE_LINE]
5665 for grd in changed_grds:
5666 for i, line in enumerate(grd.NewContents()):
5667 for matcher, msg in invalid_file_regexes:
5668 if matcher.search(line):
5669 errors.append(
5670 output_api.PresubmitError(
5671 'Problem on {grd}:{i} - {msg}'.format(
5672 grd=grd.LocalPath(), i=i + 1, msg=msg)))
5673 return errors
5674
Kevin McNee967dd2d22021-11-15 16:09:295675
5676def CheckMPArchApiUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505677 """CC the MPArch watchlist if the CL uses an API that is ambiguous in the
5678 presence of MPArch features such as bfcache, prerendering, and fenced frames.
5679 """
Kevin McNee967dd2d22021-11-15 16:09:295680
Ian Vollickdba956c2022-04-20 23:53:455681 # Only consider top-level directories that (1) can use content APIs or
5682 # problematic blink APIs, (2) apply to desktop or android chrome, and (3)
5683 # are known to have a significant number of uses of the APIs of concern.
Sam Maiera6e76d72022-02-11 21:43:505684 files_to_check = (
Ian Vollickdba956c2022-04-20 23:53:455685 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Kevin McNee967dd2d22021-11-15 16:09:295686 _IMPLEMENTATION_EXTENSIONS,
Ian Vollickdba956c2022-04-20 23:53:455687 r'^(chrome|components|content|extensions|third_party[\\/]blink[\\/]renderer)[\\/].+%s' %
Sam Maiera6e76d72022-02-11 21:43:505688 _HEADER_EXTENSIONS,
5689 )
5690 files_to_skip = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
5691 input_api.DEFAULT_FILES_TO_SKIP)
5692 source_file_filter = lambda f: input_api.FilterSourceFile(
5693 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
Kevin McNee967dd2d22021-11-15 16:09:295694
Sam Maiera6e76d72022-02-11 21:43:505695 # Note that since these are are just regular expressions and we don't have
5696 # the compiler's AST, we could have spurious matches (e.g. an unrelated class
5697 # could have a method named IsInMainFrame).
5698 concerning_class_pattern = input_api.re.compile(
5699 r'WebContentsObserver|WebContentsUserData')
5700 # A subset of WebContentsObserver overrides where there's particular risk for
5701 # confusing tab and page level operations and data (e.g. incorrectly
5702 # resetting page state in DidFinishNavigation).
5703 concerning_wco_methods = [
5704 'DidStartNavigation',
5705 'ReadyToCommitNavigation',
5706 'DidFinishNavigation',
5707 'RenderViewReady',
5708 'RenderViewDeleted',
5709 'RenderViewHostChanged',
5710 'PrimaryMainDocumentElementAvailable',
5711 'DocumentOnLoadCompletedInPrimaryMainFrame',
5712 'DOMContentLoaded',
5713 'DidFinishLoad',
5714 ]
5715 concerning_nav_handle_methods = [
5716 'IsInMainFrame',
5717 ]
5718 concerning_web_contents_methods = [
5719 'ForEachFrame',
5720 'GetAllFrames',
5721 'FromRenderFrameHost',
5722 'FromRenderViewHost',
5723 'GetMainFrame',
5724 'GetRenderViewHost',
5725 ]
5726 concerning_rfh_methods = [
5727 'GetParent',
5728 'GetMainFrame',
5729 'GetFrameTreeNodeId',
5730 ]
Ian Vollickc825b1f2022-04-19 14:30:155731 concerning_rfhi_methods = [
5732 'is_main_frame',
5733 ]
Ian Vollicka77a73ea2022-04-06 18:08:015734 concerning_ftn_methods = [
5735 'IsMainFrame',
5736 ]
Ian Vollickdba956c2022-04-20 23:53:455737 concerning_blink_frame_methods = [
5738 'IsCrossOriginToMainFrame',
5739 ]
Sam Maiera6e76d72022-02-11 21:43:505740 concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join(
5741 item for sublist in [
5742 concerning_wco_methods, concerning_nav_handle_methods,
Ian Vollicka77a73ea2022-04-06 18:08:015743 concerning_web_contents_methods, concerning_rfh_methods,
Ian Vollickc825b1f2022-04-19 14:30:155744 concerning_rfhi_methods, concerning_ftn_methods,
Ian Vollickdba956c2022-04-20 23:53:455745 concerning_blink_frame_methods,
Sam Maiera6e76d72022-02-11 21:43:505746 ] for item in sublist) + r')\(')
Kevin McNee967dd2d22021-11-15 16:09:295747
Kevin McNee4eeec792022-02-14 20:02:045748 used_apis = set()
Sam Maiera6e76d72022-02-11 21:43:505749 for f in input_api.AffectedFiles(include_deletes=False,
5750 file_filter=source_file_filter):
5751 for line_num, line in f.ChangedContents():
Kevin McNee4eeec792022-02-14 20:02:045752 class_match = concerning_class_pattern.search(line)
5753 if class_match:
5754 used_apis.add(class_match[0])
5755 method_match = concerning_method_pattern.search(line)
5756 if method_match:
5757 used_apis.add(method_match[1])
Sam Maiera6e76d72022-02-11 21:43:505758
Kevin McNee4eeec792022-02-14 20:02:045759 if not used_apis:
5760 return []
Kevin McNee967dd2d22021-11-15 16:09:295761
Kevin McNee4eeec792022-02-14 20:02:045762 output_api.AppendCC('[email protected]')
5763 message = ('This change uses API(s) that are ambiguous in the presence of '
5764 'MPArch features such as bfcache, prerendering, and fenced '
5765 'frames.')
5766 explaination = (
5767 'Please double check whether new code assumes that a WebContents only '
5768 'contains a single page at a time. For example, it is discouraged to '
5769 'reset per-document state in response to the observation of a '
5770 'navigation. See this doc [1] and the comments on the individual APIs '
5771 'for guidance and this doc [2] for context. The MPArch review '
5772 'watchlist has been CC\'d on this change to help identify any issues.\n'
5773 '[1] https://docs.google.com/document/d/13l16rWTal3o5wce4i0RwdpMP5ESELLKr439Faj2BBRo/edit?usp=sharing\n'
5774 '[2] https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing'
5775 )
5776 return [
5777 output_api.PresubmitNotifyResult(message,
5778 items=list(used_apis),
5779 long_text=explaination)
5780 ]
Henrique Ferreiro2a4b55942021-11-29 23:45:365781
5782
5783def CheckAssertAshOnlyCode(input_api, output_api):
5784 """Errors if a BUILD.gn file in an ash/ directory doesn't include
5785 assert(is_chromeos_ash).
5786 """
5787
5788 def FileFilter(affected_file):
5789 """Includes directories known to be Ash only."""
5790 return input_api.FilterSourceFile(
5791 affected_file,
5792 files_to_check=(
5793 r'^ash/.*BUILD\.gn', # Top-level src/ash/.
5794 r'.*/ash/.*BUILD\.gn'), # Any path component.
5795 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
5796
5797 errors = []
5798 pattern = input_api.re.compile(r'assert\(is_chromeos_ash')
Jameson Thies0ce669f2021-12-09 15:56:565799 for f in input_api.AffectedFiles(include_deletes=False,
5800 file_filter=FileFilter):
Henrique Ferreiro2a4b55942021-11-29 23:45:365801 if (not pattern.search(input_api.ReadFile(f))):
5802 errors.append(
5803 output_api.PresubmitError(
5804 'Please add assert(is_chromeos_ash) to %s. If that\'s not '
5805 'possible, please create and issue and add a comment such '
5806 'as:\n # TODO(https://crbug.com/XXX): add '
5807 'assert(is_chromeos_ash) when ...' % f.LocalPath()))
5808 return errors
Lukasz Anforowicz7016d05e2021-11-30 03:56:275809
5810
5811def _IsRendererOnlyCppFile(input_api, affected_file):
Sam Maiera6e76d72022-02-11 21:43:505812 path = affected_file.LocalPath()
5813 if not _IsCPlusPlusFile(input_api, path):
5814 return False
5815
5816 # Any code under a "renderer" subdirectory is assumed to be Renderer-only.
5817 if "/renderer/" in path:
5818 return True
5819
5820 # Blink's public/web API is only used/included by Renderer-only code. Note
5821 # that public/platform API may be used in non-Renderer processes (e.g. there
5822 # are some includes in code used by Utility, PDF, or Plugin processes).
5823 if "/blink/public/web/" in path:
5824 return True
5825
5826 # We assume that everything else may be used outside of Renderer processes.
Lukasz Anforowicz7016d05e2021-11-30 03:56:275827 return False
5828
Lukasz Anforowicz7016d05e2021-11-30 03:56:275829# TODO(https://crbug.com/1273182): Remove these checks, once they are replaced
5830# by the Chromium Clang Plugin (which will be preferable because it will
5831# 1) report errors earlier - at compile-time and 2) cover more rules).
5832def CheckRawPtrUsage(input_api, output_api):
Sam Maiera6e76d72022-02-11 21:43:505833 """Rough checks that raw_ptr<T> usage guidelines are followed."""
5834 errors = []
5835 # The regex below matches "raw_ptr<" following a word boundary, but not in a
5836 # C++ comment.
5837 raw_ptr_matcher = input_api.re.compile(r'^((?!//).)*\braw_ptr<')
5838 file_filter = lambda f: _IsRendererOnlyCppFile(input_api, f)
5839 for f, line_num, line in input_api.RightHandSideLines(file_filter):
5840 if raw_ptr_matcher.search(line):
5841 errors.append(
5842 output_api.PresubmitError(
5843 'Problem on {path}:{line} - '\
5844 'raw_ptr<T> should not be used in Renderer-only code '\
5845 '(as documented in the "Pointers to unprotected memory" '\
5846 'section in //base/memory/raw_ptr.md)'.format(
5847 path=f.LocalPath(), line=line_num)))
5848 return errors
Henrique Ferreirof9819f2e32021-11-30 13:31:565849
5850
5851def CheckPythonShebang(input_api, output_api):
5852 """Checks that python scripts use #!/usr/bin/env instead of hardcoding a
5853 system-wide python.
5854 """
5855 errors = []
5856 sources = lambda affected_file: input_api.FilterSourceFile(
5857 affected_file,
5858 files_to_skip=((_THIRD_PARTY_EXCEPT_BLINK,
5859 r'third_party/blink/web_tests/external/') + input_api.
5860 DEFAULT_FILES_TO_SKIP),
5861 files_to_check=[r'.*\.py$'])
5862 for f in input_api.AffectedSourceFiles(sources):
Takuto Ikuta36976512021-11-30 23:15:275863 for line_num, line in f.ChangedContents():
5864 if line_num == 1 and line.startswith('#!/usr/bin/python'):
5865 errors.append(f.LocalPath())
5866 break
Henrique Ferreirof9819f2e32021-11-30 13:31:565867
5868 result = []
5869 for file in errors:
5870 result.append(
5871 output_api.PresubmitError(
5872 "Please use '#!/usr/bin/env python/2/3' as the shebang of %s" %
5873 file))
5874 return result