blob: 5f7348d4c7ef6b7e892d9b0f8694dd300c051ce5 [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"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0447 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1851 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4452 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0453 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0554 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0455 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4756 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0457 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0858 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0459 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4460)
[email protected]ca8d1982009-02-19 16:33:1261
Daniel Bratell609102be2019-03-27 20:53:2162_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1563
[email protected]eea609a2011-11-18 13:10:1264_TEST_ONLY_WARNING = (
65 'You might be calling functions intended only for testing from\n'
66 'production code. It is OK to ignore this warning if you know what\n'
67 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5868 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1269
70
[email protected]cf9b78f2012-11-14 11:40:2871_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4072 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2173 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
74 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2875
wnwenbdc444e2016-05-25 13:44:1576
Daniel Bratell609102be2019-03-27 20:53:2177# Format: Sequence of tuples containing:
78# * String pattern or, if starting with a slash, a regular expression.
79# * Sequence of strings to show when the pattern matches.
80# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4181_BANNED_JAVA_FUNCTIONS = (
82 (
83 'StrictMode.allowThreadDiskReads()',
84 (
85 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
86 'directly.',
87 ),
88 False,
89 ),
90 (
91 'StrictMode.allowThreadDiskWrites()',
92 (
93 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
94 'directly.',
95 ),
96 False,
97 ),
98)
99
Daniel Bratell609102be2019-03-27 20:53:21100# Format: Sequence of tuples containing:
101# * String pattern or, if starting with a slash, a regular expression.
102# * Sequence of strings to show when the pattern matches.
103# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59104_BANNED_OBJC_FUNCTIONS = (
105 (
106 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20107 (
108 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59109 'prohibited. Please use CrTrackingArea instead.',
110 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
111 ),
112 False,
113 ),
114 (
[email protected]eaae1972014-04-16 04:17:26115 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20116 (
117 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59118 'instead.',
119 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
120 ),
121 False,
122 ),
123 (
124 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59127 'Please use |convertPoint:(point) fromView:nil| instead.',
128 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
129 ),
130 True,
131 ),
132 (
133 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20134 (
135 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59136 'Please use |convertPoint:(point) toView:nil| instead.',
137 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
138 ),
139 True,
140 ),
141 (
142 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20143 (
144 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59145 'Please use |convertRect:(point) fromView:nil| instead.',
146 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
147 ),
148 True,
149 ),
150 (
151 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20152 (
153 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59154 'Please use |convertRect:(point) toView:nil| instead.',
155 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
156 ),
157 True,
158 ),
159 (
160 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20161 (
162 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59163 'Please use |convertSize:(point) fromView:nil| instead.',
164 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
165 ),
166 True,
167 ),
168 (
169 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59172 'Please use |convertSize:(point) toView:nil| instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 True,
176 ),
jif65398702016-10-27 10:19:48177 (
178 r"/\s+UTF8String\s*]",
179 (
180 'The use of -[NSString UTF8String] is dangerous as it can return null',
181 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
182 'Please use |SysNSStringToUTF8| instead.',
183 ),
184 True,
185 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34186 (
187 r'__unsafe_unretained',
188 (
189 'The use of __unsafe_unretained is almost certainly wrong, unless',
190 'when interacting with NSFastEnumeration or NSInvocation.',
191 'Please use __weak in files build with ARC, nothing otherwise.',
192 ),
193 False,
194 ),
[email protected]127f18ec2012-06-16 05:05:59195)
196
Daniel Bratell609102be2019-03-27 20:53:21197# Format: Sequence of tuples containing:
198# * String pattern or, if starting with a slash, a regular expression.
199# * Sequence of strings to show when the pattern matches.
200# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54201_BANNED_IOS_OBJC_FUNCTIONS = (
202 (
203 r'/\bTEST[(]',
204 (
205 'TEST() macro should not be used in Objective-C++ code as it does not ',
206 'drain the autorelease pool at the end of the test. Use TEST_F() ',
207 'macro instead with a fixture inheriting from PlatformTest (or a ',
208 'typedef).'
209 ),
210 True,
211 ),
212 (
213 r'/\btesting::Test\b',
214 (
215 'testing::Test should not be used in Objective-C++ code as it does ',
216 'not drain the autorelease pool at the end of the test. Use ',
217 'PlatformTest instead.'
218 ),
219 True,
220 ),
221)
222
[email protected]127f18ec2012-06-16 05:05:59223
Daniel Bratell609102be2019-03-27 20:53:21224# Format: Sequence of tuples containing:
225# * String pattern or, if starting with a slash, a regular expression.
226# * Sequence of strings to show when the pattern matches.
227# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
228# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59229_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20230 (
thomasandersone7caaa9b2017-03-29 19:22:53231 r'\bNULL\b',
232 (
233 'New code should not use NULL. Use nullptr instead.',
234 ),
235 True,
236 (),
237 ),
Antonio Gomes07300d02019-03-13 20:59:57238 # Make sure that gtest's FRIEND_TEST() macro is not used; the
239 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
240 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53241 (
[email protected]23e6cbc2012-06-16 18:51:20242 'FRIEND_TEST(',
243 (
[email protected]e3c945502012-06-26 20:01:49244 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20245 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
246 ),
247 False,
[email protected]7345da02012-11-27 14:31:49248 (),
[email protected]23e6cbc2012-06-16 18:51:20249 ),
250 (
thomasanderson4b569052016-09-14 20:15:53251 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
252 (
253 'Chrome clients wishing to select events on X windows should use',
254 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
255 'you are selecting events from the GPU process, or if you are using',
256 'an XDisplay other than gfx::GetXDisplay().',
257 ),
258 True,
259 (
Egor Paskoce145c42018-09-28 19:31:04260 r"^ui[\\/]gl[\\/].*\.cc$",
261 r"^media[\\/]gpu[\\/].*\.cc$",
262 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53263 ),
264 ),
265 (
thomasandersone043e3ce2017-06-08 00:43:20266 r'XInternAtom|xcb_intern_atom',
267 (
thomasanderson11aa41d2017-06-08 22:22:38268 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20269 ),
270 True,
271 (
Egor Paskoce145c42018-09-28 19:31:04272 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
273 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
274 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20275 ),
276 ),
277 (
tomhudsone2c14d552016-05-26 17:07:46278 'setMatrixClip',
279 (
280 'Overriding setMatrixClip() is prohibited; ',
281 'the base function is deprecated. ',
282 ),
283 True,
284 (),
285 ),
286 (
[email protected]52657f62013-05-20 05:30:31287 'SkRefPtr',
288 (
289 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22290 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31291 ),
292 True,
293 (),
294 ),
295 (
296 'SkAutoRef',
297 (
298 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
304 (
305 'SkAutoTUnref',
306 (
307 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22308 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31309 ),
310 True,
311 (),
312 ),
313 (
314 'SkAutoUnref',
315 (
316 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
317 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22318 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31319 ),
320 True,
321 (),
322 ),
[email protected]d89eec82013-12-03 14:10:59323 (
324 r'/HANDLE_EINTR\(.*close',
325 (
326 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
327 'descriptor will be closed, and it is incorrect to retry the close.',
328 'Either call close directly and ignore its return value, or wrap close',
329 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
330 ),
331 True,
332 (),
333 ),
334 (
335 r'/IGNORE_EINTR\((?!.*close)',
336 (
337 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
338 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
339 ),
340 True,
341 (
342 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04343 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
344 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59345 ),
346 ),
[email protected]ec5b3f02014-04-04 18:43:43347 (
348 r'/v8::Extension\(',
349 (
350 'Do not introduce new v8::Extensions into the code base, use',
351 'gin::Wrappable instead. See http://crbug.com/334679',
352 ),
353 True,
[email protected]f55c90ee62014-04-12 00:50:03354 (
Egor Paskoce145c42018-09-28 19:31:04355 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03356 ),
[email protected]ec5b3f02014-04-04 18:43:43357 ),
skyostilf9469f72015-04-20 10:38:52358 (
jame2d1a952016-04-02 00:27:10359 '#pragma comment(lib,',
360 (
361 'Specify libraries to link with in build files and not in the source.',
362 ),
363 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41364 (
tzik3f295992018-12-04 20:32:23365 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04366 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41367 ),
jame2d1a952016-04-02 00:27:10368 ),
fdorayc4ac18d2017-05-01 21:39:59369 (
Gabriel Charette7cc6c432018-04-25 20:52:02370 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59371 (
372 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
373 ),
374 False,
375 (),
376 ),
377 (
Gabriel Charette7cc6c432018-04-25 20:52:02378 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59379 (
380 'Consider using THREAD_CHECKER macros instead of the class directly.',
381 ),
382 False,
383 (),
384 ),
dbeamb6f4fde2017-06-15 04:03:06385 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06386 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
387 (
388 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
389 'deprecated (http://crbug.com/634507). Please avoid converting away',
390 'from the Time types in Chromium code, especially if any math is',
391 'being done on time values. For interfacing with platform/library',
392 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
393 'type converter methods instead. For faking TimeXXX values (for unit',
394 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
395 'other use cases, please contact base/time/OWNERS.',
396 ),
397 False,
398 (),
399 ),
400 (
dbeamb6f4fde2017-06-15 04:03:06401 'CallJavascriptFunctionUnsafe',
402 (
403 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
404 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
405 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
406 ),
407 False,
408 (
Egor Paskoce145c42018-09-28 19:31:04409 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
410 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
411 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06412 ),
413 ),
dskiba1474c2bfd62017-07-20 02:19:24414 (
415 'leveldb::DB::Open',
416 (
417 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
418 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
419 "Chrome's tracing, making their memory usage visible.",
420 ),
421 True,
422 (
423 r'^third_party/leveldatabase/.*\.(cc|h)$',
424 ),
Gabriel Charette0592c3a2017-07-26 12:02:04425 ),
426 (
Chris Mumfordc38afb62017-10-09 17:55:08427 'leveldb::NewMemEnv',
428 (
429 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58430 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
431 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08432 ),
433 True,
434 (
435 r'^third_party/leveldatabase/.*\.(cc|h)$',
436 ),
437 ),
438 (
Gabriel Charetted9839bc2017-07-29 14:17:47439 'RunLoop::QuitCurrent',
440 (
Robert Liao64b7ab22017-08-04 23:03:43441 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
442 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47443 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41444 False,
Gabriel Charetted9839bc2017-07-29 14:17:47445 (),
Gabriel Charettea44975052017-08-21 23:14:04446 ),
447 (
448 'base::ScopedMockTimeMessageLoopTaskRunner',
449 (
Gabriel Charette87cc1af2018-04-25 20:52:51450 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
451 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
452 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
453 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
454 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04455 ),
Gabriel Charette87cc1af2018-04-25 20:52:51456 False,
Gabriel Charettea44975052017-08-21 23:14:04457 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57458 ),
459 (
460 r'std::regex',
461 (
462 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02463 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57464 ),
465 True,
466 (),
Francois Doray43670e32017-09-27 12:40:38467 ),
468 (
Daniel Bratell69334cc2019-03-26 11:07:45469 r'/\bstd::to_string\b',
470 (
471 'std::to_string is locale dependent and slower than alternatives.',
472 'For locale-independent strings, e.g. writing numbers to and from',
473 'disk profiles, use base::NumberToString().',
474 'For user-visible strings, use base::FormatNumber() and',
475 'the related functions in base/i18n/number_formatting.h.',
476 ),
477 False, # Only a warning for now since it is already used,
Daniel Bratell609102be2019-03-27 20:53:21478 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45479 ),
480 (
481 r'/\bstd::shared_ptr\b',
482 (
483 'std::shared_ptr should not be used. Use scoped_refptr instead.',
484 ),
485 True,
Daniel Bratell609102be2019-03-27 20:53:21486 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
487 ),
488 (
489 r'/\blong long\b',
490 (
491 'long long is banned. Use stdint.h if you need a 64 bit number.',
492 ),
493 False, # Only a warning since it is already used.
494 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
495 ),
496 (
497 r'/\bstd::bind\b',
498 (
499 'std::bind is banned because of lifetime risks.',
500 'Use base::BindOnce or base::BindRepeating instead.',
501 ),
502 True,
503 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
504 ),
505 (
506 r'/\b#include <chrono>\b',
507 (
508 '<chrono> overlaps with Time APIs in base. Keep using',
509 'base classes.',
510 ),
511 True,
512 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
513 ),
514 (
515 r'/\b#include <exception>\b',
516 (
517 'Exceptions are banned and disabled in Chromium.',
518 ),
519 True,
520 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
521 ),
522 (
523 r'/\bstd::function\b',
524 (
525 'std::function is banned. Instead use base::Callback which directly',
526 'supports Chromium\'s weak pointers, ref counting and more.',
527 ),
528 False, # Only a warning since there are dozens of uses already.
529 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
530 ),
531 (
532 r'/\b#include <random>\b',
533 (
534 'Do not use any random number engines from <random>. Instead',
535 'use base::RandomBitGenerator.',
536 ),
537 True,
538 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
539 ),
540 (
541 r'/\bstd::ratio\b',
542 (
543 'std::ratio is banned by the Google Style Guide.',
544 ),
545 True,
546 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45547 ),
548 (
Francois Doray43670e32017-09-27 12:40:38549 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
550 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
551 (
552 'Use the new API in base/threading/thread_restrictions.h.',
553 ),
Gabriel Charette04b138f2018-08-06 00:03:22554 False,
Francois Doray43670e32017-09-27 12:40:38555 (),
556 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38557 (
558 r'/\bbase::Bind\(',
559 (
Gabriel Charette147335ea2018-03-22 15:59:19560 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02561 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38562 ),
563 False,
564 (),
565 ),
566 (
567 r'/\bbase::Callback<',
568 (
Gabriel Charette147335ea2018-03-22 15:59:19569 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02570 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38571 ),
572 False,
573 (),
574 ),
575 (
576 r'/\bbase::Closure\b',
577 (
Gabriel Charette147335ea2018-03-22 15:59:19578 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02579 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38580 ),
581 False,
582 (),
583 ),
Victor Costan3653df62018-02-08 21:38:16584 (
Alex Ilin5929abe32019-04-03 17:09:34585 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45586 (
587 'base::SharedMemory is deprecated. Please use',
588 '{Writable,ReadOnly}SharedMemoryRegion instead.',
589 ),
590 False,
591 (),
592 ),
593 (
Michael Giuffrida7f93d6922019-04-19 14:39:58594 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19595 (
596 'RunMessageLoop is deprecated, use RunLoop instead.',
597 ),
598 False,
599 (),
600 ),
601 (
602 r'RunThisRunLoop',
603 (
604 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
605 ),
606 False,
607 (),
608 ),
609 (
610 r'RunAllPendingInMessageLoop()',
611 (
612 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
613 "if you're convinced you need this.",
614 ),
615 False,
616 (),
617 ),
618 (
619 r'RunAllPendingInMessageLoop(BrowserThread',
620 (
621 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
622 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
623 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
624 'async events instead of flushing threads.',
625 ),
626 False,
627 (),
628 ),
629 (
630 r'MessageLoopRunner',
631 (
632 'MessageLoopRunner is deprecated, use RunLoop instead.',
633 ),
634 False,
635 (),
636 ),
637 (
638 r'GetDeferredQuitTaskForRunLoop',
639 (
640 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
641 "gab@ if you found a use case where this is the only solution.",
642 ),
643 False,
644 (),
645 ),
646 (
Victor Costane48a2e82019-03-15 22:02:34647 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16648 (
Victor Costane48a2e82019-03-15 22:02:34649 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16650 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
651 ),
652 True,
653 (
654 r'^sql/initialization\.(cc|h)$',
655 r'^third_party/sqlite/.*\.(c|cc|h)$',
656 ),
657 ),
Matt Menke7f520a82018-03-28 21:38:37658 (
659 'net::URLFetcher',
660 (
661 'net::URLFetcher should no longer be used in content embedders. ',
662 'Instead, use network::SimpleURLLoader instead, which supports ',
663 'an out-of-process network stack. ',
664 'net::URLFetcher may still be used in binaries that do not embed',
665 'content.',
666 ),
Matt Menke59716d02018-04-05 12:45:53667 False,
Matt Menke7f520a82018-03-28 21:38:37668 (
Egor Paskoce145c42018-09-28 19:31:04669 r'^ios[\\/].*\.(cc|h)$',
670 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37671 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04672 r'^net[\\/].*\.(cc|h)$',
673 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37674 ),
675 ),
jdoerried7d10ab2018-04-27 10:46:13676 (
tzik5de2157f2018-05-08 03:42:47677 r'std::random_shuffle',
678 (
679 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
680 'base::RandomShuffle instead.'
681 ),
682 True,
683 (),
684 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24685 (
686 'ios/web/public/test/http_server',
687 (
688 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
689 ),
690 False,
691 (),
692 ),
Robert Liao764c9492019-01-24 18:46:28693 (
694 'GetAddressOf',
695 (
696 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
697 'implicated in a few leaks. Use operator& instead.'
698 ),
699 True,
700 (),
701 ),
Antonio Gomes07300d02019-03-13 20:59:57702 (
703 'DEFINE_TYPE_CASTS',
704 (
705 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
706 '//third_party/blink/renderer/platform/casting.h.'
707 ),
708 True,
709 (
710 r'^third_party/blink/renderer/.*\.(cc|h)$',
711 ),
712 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38713 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37714 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38715 (
716 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
717 ),
718 True,
719 (),
720 ),
[email protected]127f18ec2012-06-16 05:05:59721)
722
wnwenbdc444e2016-05-25 13:44:15723
mlamouria82272622014-09-16 18:45:04724_IPC_ENUM_TRAITS_DEPRECATED = (
725 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50726 'See http://www.chromium.org/Home/chromium-security/education/'
727 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04728
Stephen Martinis97a394142018-06-07 23:06:05729_LONG_PATH_ERROR = (
730 'Some files included in this CL have file names that are too long (> 200'
731 ' characters). If committed, these files will cause issues on Windows. See'
732 ' https://crbug.com/612667 for more details.'
733)
734
Shenghua Zhangbfaa38b82017-11-16 21:58:02735_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04736 r".*[\\/]BuildHooksAndroidImpl\.java",
737 r".*[\\/]LicenseContentProvider\.java",
738 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28739 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02740]
[email protected]127f18ec2012-06-16 05:05:59741
Sean Kau46e29bc2017-08-28 16:31:16742# These paths contain test data and other known invalid JSON files.
743_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04744 r'test[\\/]data[\\/]',
745 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
746 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04747 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43748 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16749]
750
751
[email protected]b00342e7f2013-03-26 16:21:54752_VALID_OS_MACROS = (
753 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08754 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54755 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12756 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54757 'OS_BSD',
758 'OS_CAT', # For testing.
759 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04760 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54761 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37762 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54763 'OS_IOS',
764 'OS_LINUX',
765 'OS_MACOSX',
766 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21767 'OS_NACL_NONSFI',
768 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12769 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54770 'OS_OPENBSD',
771 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37772 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54773 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54774 'OS_WIN',
775)
776
777
agrievef32bcc72016-04-04 14:57:40778_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39779 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36780 'base/android/jni_generator/jni_generator.pydeps',
781 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:22782 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36783 'build/android/gyp/aar.pydeps',
784 'build/android/gyp/aidl.pydeps',
785 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38786 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36787 'build/android/gyp/bytecode_processor.pydeps',
788 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57789 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36790 'build/android/gyp/create_bundle_wrapper_script.pydeps',
791 'build/android/gyp/copy_ex.pydeps',
792 'build/android/gyp/create_app_bundle.pydeps',
793 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36794 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22795 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36796 'build/android/gyp/create_stack_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36797 'build/android/gyp/create_tool_wrapper.pydeps',
798 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59799 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36800 'build/android/gyp/dex.pydeps',
801 'build/android/gyp/dist_aar.pydeps',
802 'build/android/gyp/emma_instr.pydeps',
803 'build/android/gyp/filter_zip.pydeps',
804 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36805 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36806 'build/android/gyp/ijar.pydeps',
807 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26808 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36809 'build/android/gyp/javac.pydeps',
810 'build/android/gyp/jinja_template.pydeps',
811 'build/android/gyp/lint.pydeps',
812 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36813 'build/android/gyp/merge_manifest.pydeps',
814 'build/android/gyp/prepare_resources.pydeps',
815 'build/android/gyp/proguard.pydeps',
816 'build/android/gyp/write_build_config.pydeps',
817 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56818 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36819 'build/android/incremental_install/generate_android_manifest.pydeps',
820 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22821 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40822 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04823 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36824 'build/protoc_java.pydeps',
agrieve732db3a2016-04-26 19:18:19825 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:02826 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:40827]
828
wnwenbdc444e2016-05-25 13:44:15829
agrievef32bcc72016-04-04 14:57:40830_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40831 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29832 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
John Budorickbc3571aa2019-04-25 02:20:06833 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22834 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40835]
836
wnwenbdc444e2016-05-25 13:44:15837
agrievef32bcc72016-04-04 14:57:40838_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
839
840
Eric Boren6fd2b932018-01-25 15:05:08841# Bypass the AUTHORS check for these accounts.
842_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29843 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
844 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08845 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32846 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59847 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45848 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59849 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22850 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04851 ) | set('%[email protected]' % s
852 for s in ('chromium-autoroll',)
853 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30854 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08855
856
Daniel Bratell65b033262019-04-23 08:17:06857def _IsCPlusPlusFile(input_api, file_path):
858 """Returns True if this file contains C++-like code (and not Python,
859 Go, Java, MarkDown, ...)"""
860
861 ext = input_api.os_path.splitext(file_path)[1]
862 # This list is compatible with CppChecker.IsCppFile but we should
863 # consider adding ".c" to it. If we do that we can use this function
864 # at more places in the code.
865 return ext in (
866 '.h',
867 '.cc',
868 '.cpp',
869 '.m',
870 '.mm',
871 )
872
873def _IsCPlusPlusHeaderFile(input_api, file_path):
874 return input_api.os_path.splitext(file_path)[1] == ".h"
875
876
877def _IsJavaFile(input_api, file_path):
878 return input_api.os_path.splitext(file_path)[1] == ".java"
879
880
881def _IsProtoFile(input_api, file_path):
882 return input_api.os_path.splitext(file_path)[1] == ".proto"
883
[email protected]55459852011-08-10 15:17:19884def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
885 """Attempts to prevent use of functions intended only for testing in
886 non-testing code. For now this is just a best-effort implementation
887 that ignores header files and may have some false positives. A
888 better implementation would probably need a proper C++ parser.
889 """
890 # We only scan .cc files and the like, as the declaration of
891 # for-testing functions in header files are hard to distinguish from
892 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49893 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19894
jochenc0d4808c2015-07-27 09:25:42895 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19896 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09897 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19898 exclusion_pattern = input_api.re.compile(
899 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
900 base_function_pattern, base_function_pattern))
901
902 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44903 black_list = (_EXCLUDED_PATHS +
904 _TEST_CODE_EXCLUDED_PATHS +
905 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19906 return input_api.FilterSourceFile(
907 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49908 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19909 black_list=black_list)
910
911 problems = []
912 for f in input_api.AffectedSourceFiles(FilterFile):
913 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24914 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03915 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46916 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03917 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19918 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03919 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19920
921 if problems:
[email protected]f7051d52013-04-02 18:31:42922 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03923 else:
924 return []
[email protected]55459852011-08-10 15:17:19925
926
Vaclav Brozek7dbc28c2018-03-27 08:35:23927def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
928 """This is a simplified version of
929 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
930 """
931 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
932 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
933 name_pattern = r'ForTest(s|ing)?'
934 # Describes an occurrence of "ForTest*" inside a // comment.
935 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
936 # Catch calls.
937 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
938 # Ignore definitions. (Comments are ignored separately.)
939 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
940
941 problems = []
942 sources = lambda x: input_api.FilterSourceFile(
943 x,
944 black_list=(('(?i).*test', r'.*\/junit\/')
945 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49946 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23947 )
948 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
949 local_path = f.LocalPath()
950 is_inside_javadoc = False
951 for line_number, line in f.ChangedContents():
952 if is_inside_javadoc and javadoc_end_re.search(line):
953 is_inside_javadoc = False
954 if not is_inside_javadoc and javadoc_start_re.search(line):
955 is_inside_javadoc = True
956 if is_inside_javadoc:
957 continue
958 if (inclusion_re.search(line) and
959 not comment_re.search(line) and
960 not exclusion_re.search(line)):
961 problems.append(
962 '%s:%d\n %s' % (local_path, line_number, line.strip()))
963
964 if problems:
965 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
966 else:
967 return []
968
969
[email protected]10689ca2011-09-02 02:31:54970def _CheckNoIOStreamInHeaders(input_api, output_api):
971 """Checks to make sure no .h files include <iostream>."""
972 files = []
973 pattern = input_api.re.compile(r'^#include\s*<iostream>',
974 input_api.re.MULTILINE)
975 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
976 if not f.LocalPath().endswith('.h'):
977 continue
978 contents = input_api.ReadFile(f)
979 if pattern.search(contents):
980 files.append(f)
981
982 if len(files):
yolandyandaabc6d2016-04-18 18:29:39983 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06984 'Do not #include <iostream> in header files, since it inserts static '
985 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54986 '#include <ostream>. See http://crbug.com/94794',
987 files) ]
988 return []
989
Danil Chapovalov3518f362018-08-11 16:13:43990def _CheckNoStrCatRedefines(input_api, output_api):
991 """Checks no windows headers with StrCat redefined are included directly."""
992 files = []
993 pattern_deny = input_api.re.compile(
994 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
995 input_api.re.MULTILINE)
996 pattern_allow = input_api.re.compile(
997 r'^#include\s"base/win/windows_defines.inc"',
998 input_api.re.MULTILINE)
999 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1000 contents = input_api.ReadFile(f)
1001 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1002 files.append(f.LocalPath())
1003
1004 if len(files):
1005 return [output_api.PresubmitError(
1006 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1007 'directly since they pollute code with StrCat macro. Instead, '
1008 'include matching header from base/win. See http://crbug.com/856536',
1009 files) ]
1010 return []
1011
[email protected]10689ca2011-09-02 02:31:541012
[email protected]72df4e782012-06-21 16:28:181013def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521014 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181015 problems = []
1016 for f in input_api.AffectedFiles():
1017 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1018 continue
1019
1020 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041021 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181022 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1023
1024 if not problems:
1025 return []
1026 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1027 '\n'.join(problems))]
1028
Dominic Battre033531052018-09-24 15:45:341029def _CheckNoDISABLETypoInTests(input_api, output_api):
1030 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1031
1032 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1033 instead of DISABLED_. To filter false positives, reports are only generated
1034 if a corresponding MAYBE_ line exists.
1035 """
1036 problems = []
1037
1038 # The following two patterns are looked for in tandem - is a test labeled
1039 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1040 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1041 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1042
1043 # This is for the case that a test is disabled on all platforms.
1044 full_disable_pattern = input_api.re.compile(
1045 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1046 input_api.re.MULTILINE)
1047
Katie Df13948e2018-09-25 07:33:441048 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341049 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1050 continue
1051
1052 # Search for MABYE_, DISABLE_ pairs.
1053 disable_lines = {} # Maps of test name to line number.
1054 maybe_lines = {}
1055 for line_num, line in f.ChangedContents():
1056 disable_match = disable_pattern.search(line)
1057 if disable_match:
1058 disable_lines[disable_match.group(1)] = line_num
1059 maybe_match = maybe_pattern.search(line)
1060 if maybe_match:
1061 maybe_lines[maybe_match.group(1)] = line_num
1062
1063 # Search for DISABLE_ occurrences within a TEST() macro.
1064 disable_tests = set(disable_lines.keys())
1065 maybe_tests = set(maybe_lines.keys())
1066 for test in disable_tests.intersection(maybe_tests):
1067 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1068
1069 contents = input_api.ReadFile(f)
1070 full_disable_match = full_disable_pattern.search(contents)
1071 if full_disable_match:
1072 problems.append(' %s' % f.LocalPath())
1073
1074 if not problems:
1075 return []
1076 return [
1077 output_api.PresubmitPromptWarning(
1078 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1079 '\n'.join(problems))
1080 ]
1081
[email protected]72df4e782012-06-21 16:28:181082
danakj61c1aa22015-10-26 19:55:521083def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571084 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521085 errors = []
1086 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1087 input_api.re.MULTILINE)
1088 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1089 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1090 continue
1091 for lnum, line in f.ChangedContents():
1092 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171093 errors.append(output_api.PresubmitError(
1094 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571095 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171096 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521097 return errors
1098
1099
mcasasb7440c282015-02-04 14:52:191100def _FindHistogramNameInLine(histogram_name, line):
1101 """Tries to find a histogram name or prefix in a line."""
1102 if not "affected-histogram" in line:
1103 return histogram_name in line
1104 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1105 # the histogram_name.
1106 if not '"' in line:
1107 return False
1108 histogram_prefix = line.split('\"')[1]
1109 return histogram_prefix in histogram_name
1110
1111
1112def _CheckUmaHistogramChanges(input_api, output_api):
1113 """Check that UMA histogram names in touched lines can still be found in other
1114 lines of the patch or in histograms.xml. Note that this check would not catch
1115 the reverse: changes in histograms.xml not matched in the code itself."""
1116 touched_histograms = []
1117 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471118 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1119 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1120 name_pattern = r'"(.*?)"'
1121 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1122 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1123 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1124 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1125 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171126 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191127 for f in input_api.AffectedFiles():
1128 # If histograms.xml itself is modified, keep the modified lines for later.
1129 if f.LocalPath().endswith(('histograms.xml')):
1130 histograms_xml_modifications = f.ChangedContents()
1131 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471132 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1133 single_line_re = single_line_c_re
1134 split_line_prefix_re = split_line_c_prefix_re
1135 elif f.LocalPath().endswith(('java')):
1136 single_line_re = single_line_java_re
1137 split_line_prefix_re = split_line_java_prefix_re
1138 else:
mcasasb7440c282015-02-04 14:52:191139 continue
1140 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171141 if last_line_matched_prefix:
1142 suffix_found = split_line_suffix_re.search(line)
1143 if suffix_found :
1144 touched_histograms.append([suffix_found.group(1), f, line_num])
1145 last_line_matched_prefix = False
1146 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061147 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191148 if found:
1149 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171150 continue
1151 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191152
1153 # Search for the touched histogram names in the local modifications to
1154 # histograms.xml, and, if not found, on the base histograms.xml file.
1155 unmatched_histograms = []
1156 for histogram_info in touched_histograms:
1157 histogram_name_found = False
1158 for line_num, line in histograms_xml_modifications:
1159 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1160 if histogram_name_found:
1161 break
1162 if not histogram_name_found:
1163 unmatched_histograms.append(histogram_info)
1164
eromanb90c82e7e32015-04-01 15:13:491165 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191166 problems = []
1167 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491168 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191169 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451170 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191171 histogram_name_found = False
1172 for line in histograms_xml:
1173 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1174 if histogram_name_found:
1175 break
1176 if not histogram_name_found:
1177 problems.append(' [%s:%d] %s' %
1178 (f.LocalPath(), line_num, histogram_name))
1179
1180 if not problems:
1181 return []
1182 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1183 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491184 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191185
wnwenbdc444e2016-05-25 13:44:151186
yolandyandaabc6d2016-04-18 18:29:391187def _CheckFlakyTestUsage(input_api, output_api):
1188 """Check that FlakyTest annotation is our own instead of the android one"""
1189 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1190 files = []
1191 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1192 if f.LocalPath().endswith('Test.java'):
1193 if pattern.search(input_api.ReadFile(f)):
1194 files.append(f)
1195 if len(files):
1196 return [output_api.PresubmitError(
1197 'Use org.chromium.base.test.util.FlakyTest instead of '
1198 'android.test.FlakyTest',
1199 files)]
1200 return []
mcasasb7440c282015-02-04 14:52:191201
wnwenbdc444e2016-05-25 13:44:151202
[email protected]8ea5d4b2011-09-13 21:49:221203def _CheckNoNewWStrings(input_api, output_api):
1204 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271205 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221206 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201207 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571208 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341209 '/win/' in f.LocalPath() or
1210 'chrome_elf' in f.LocalPath() or
1211 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201212 continue
[email protected]8ea5d4b2011-09-13 21:49:221213
[email protected]a11dbe9b2012-08-07 01:32:581214 allowWString = False
[email protected]b5c24292011-11-28 14:38:201215 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581216 if 'presubmit: allow wstring' in line:
1217 allowWString = True
1218 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271219 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581220 allowWString = False
1221 else:
1222 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221223
[email protected]55463aa62011-10-12 00:48:271224 if not problems:
1225 return []
1226 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581227 ' If you are calling a cross-platform API that accepts a wstring, '
1228 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271229 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221230
1231
[email protected]2a8ac9c2011-10-19 17:20:441232def _CheckNoDEPSGIT(input_api, output_api):
1233 """Make sure .DEPS.git is never modified manually."""
1234 if any(f.LocalPath().endswith('.DEPS.git') for f in
1235 input_api.AffectedFiles()):
1236 return [output_api.PresubmitError(
1237 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1238 'automated system based on what\'s in DEPS and your changes will be\n'
1239 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501240 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1241 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441242 'for more information')]
1243 return []
1244
1245
tandriief664692014-09-23 14:51:471246def _CheckValidHostsInDEPS(input_api, output_api):
1247 """Checks that DEPS file deps are from allowed_hosts."""
1248 # Run only if DEPS file has been modified to annoy fewer bystanders.
1249 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1250 return []
1251 # Outsource work to gclient verify
1252 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201253 input_api.subprocess.check_output(['gclient', 'verify'],
1254 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471255 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201256 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471257 return [output_api.PresubmitError(
1258 'DEPS file must have only git dependencies.',
1259 long_text=error.output)]
1260
1261
[email protected]127f18ec2012-06-16 05:05:591262def _CheckNoBannedFunctions(input_api, output_api):
1263 """Make sure that banned functions are not used."""
1264 warnings = []
1265 errors = []
1266
wnwenbdc444e2016-05-25 13:44:151267 def IsBlacklisted(affected_file, blacklist):
1268 local_path = affected_file.LocalPath()
1269 for item in blacklist:
1270 if input_api.re.match(item, local_path):
1271 return True
1272 return False
1273
Sylvain Defresnea8b73d252018-02-28 15:45:541274 def IsIosObcjFile(affected_file):
1275 local_path = affected_file.LocalPath()
1276 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1277 return False
1278 basename = input_api.os_path.basename(local_path)
1279 if 'ios' in basename.split('_'):
1280 return True
1281 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1282 if sep and 'ios' in local_path.split(sep):
1283 return True
1284 return False
1285
wnwenbdc444e2016-05-25 13:44:151286 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1287 matched = False
1288 if func_name[0:1] == '/':
1289 regex = func_name[1:]
1290 if input_api.re.search(regex, line):
1291 matched = True
1292 elif func_name in line:
dchenge07de812016-06-20 19:27:171293 matched = True
wnwenbdc444e2016-05-25 13:44:151294 if matched:
dchenge07de812016-06-20 19:27:171295 problems = warnings
wnwenbdc444e2016-05-25 13:44:151296 if error:
dchenge07de812016-06-20 19:27:171297 problems = errors
wnwenbdc444e2016-05-25 13:44:151298 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1299 for message_line in message:
1300 problems.append(' %s' % message_line)
1301
Eric Stevensona9a980972017-09-23 00:04:411302 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1303 for f in input_api.AffectedFiles(file_filter=file_filter):
1304 for line_num, line in f.ChangedContents():
1305 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1306 CheckForMatch(f, line_num, line, func_name, message, error)
1307
[email protected]127f18ec2012-06-16 05:05:591308 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1309 for f in input_api.AffectedFiles(file_filter=file_filter):
1310 for line_num, line in f.ChangedContents():
1311 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151312 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591313
Sylvain Defresnea8b73d252018-02-28 15:45:541314 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1315 for line_num, line in f.ChangedContents():
1316 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1317 CheckForMatch(f, line_num, line, func_name, message, error)
1318
[email protected]127f18ec2012-06-16 05:05:591319 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1320 for f in input_api.AffectedFiles(file_filter=file_filter):
1321 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491322 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491323 if IsBlacklisted(f, excluded_paths):
1324 continue
wnwenbdc444e2016-05-25 13:44:151325 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591326
1327 result = []
1328 if (warnings):
1329 result.append(output_api.PresubmitPromptWarning(
1330 'Banned functions were used.\n' + '\n'.join(warnings)))
1331 if (errors):
1332 result.append(output_api.PresubmitError(
1333 'Banned functions were used.\n' + '\n'.join(errors)))
1334 return result
1335
1336
[email protected]6c063c62012-07-11 19:11:061337def _CheckNoPragmaOnce(input_api, output_api):
1338 """Make sure that banned functions are not used."""
1339 files = []
1340 pattern = input_api.re.compile(r'^#pragma\s+once',
1341 input_api.re.MULTILINE)
1342 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1343 if not f.LocalPath().endswith('.h'):
1344 continue
1345 contents = input_api.ReadFile(f)
1346 if pattern.search(contents):
1347 files.append(f)
1348
1349 if files:
1350 return [output_api.PresubmitError(
1351 'Do not use #pragma once in header files.\n'
1352 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1353 files)]
1354 return []
1355
[email protected]127f18ec2012-06-16 05:05:591356
[email protected]e7479052012-09-19 00:26:121357def _CheckNoTrinaryTrueFalse(input_api, output_api):
1358 """Checks to make sure we don't introduce use of foo ? true : false."""
1359 problems = []
1360 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1361 for f in input_api.AffectedFiles():
1362 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1363 continue
1364
1365 for line_num, line in f.ChangedContents():
1366 if pattern.match(line):
1367 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1368
1369 if not problems:
1370 return []
1371 return [output_api.PresubmitPromptWarning(
1372 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1373 '\n'.join(problems))]
1374
1375
[email protected]55f9f382012-07-31 11:02:181376def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281377 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181378 change. Breaking - rules is an error, breaking ! rules is a
1379 warning.
1380 """
mohan.reddyf21db962014-10-16 12:26:471381 import sys
[email protected]55f9f382012-07-31 11:02:181382 # We need to wait until we have an input_api object and use this
1383 # roundabout construct to import checkdeps because this file is
1384 # eval-ed and thus doesn't have __file__.
1385 original_sys_path = sys.path
1386 try:
1387 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471388 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181389 import checkdeps
[email protected]55f9f382012-07-31 11:02:181390 from rules import Rule
1391 finally:
1392 # Restore sys.path to what it was before.
1393 sys.path = original_sys_path
1394
1395 added_includes = []
rhalavati08acd232017-04-03 07:23:281396 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241397 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181398 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061399 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501400 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081401 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061402 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501403 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081404 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061405 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501406 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081407 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181408
[email protected]26385172013-05-09 23:11:351409 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181410
1411 error_descriptions = []
1412 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281413 error_subjects = set()
1414 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181415 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1416 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081417 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181418 description_with_path = '%s\n %s' % (path, rule_description)
1419 if rule_type == Rule.DISALLOW:
1420 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281421 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181422 else:
1423 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281424 warning_subjects.add("#includes")
1425
1426 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1427 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081428 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281429 description_with_path = '%s\n %s' % (path, rule_description)
1430 if rule_type == Rule.DISALLOW:
1431 error_descriptions.append(description_with_path)
1432 error_subjects.add("imports")
1433 else:
1434 warning_descriptions.append(description_with_path)
1435 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181436
Jinsuk Kim5a092672017-10-24 22:42:241437 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021438 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081439 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241440 description_with_path = '%s\n %s' % (path, rule_description)
1441 if rule_type == Rule.DISALLOW:
1442 error_descriptions.append(description_with_path)
1443 error_subjects.add("imports")
1444 else:
1445 warning_descriptions.append(description_with_path)
1446 warning_subjects.add("imports")
1447
[email protected]55f9f382012-07-31 11:02:181448 results = []
1449 if error_descriptions:
1450 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281451 'You added one or more %s that violate checkdeps rules.'
1452 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181453 error_descriptions))
1454 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421455 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281456 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181457 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281458 '%s? See relevant DEPS file(s) for details and contacts.' %
1459 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181460 warning_descriptions))
1461 return results
1462
1463
[email protected]fbcafe5a2012-08-08 15:31:221464def _CheckFilePermissions(input_api, output_api):
1465 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151466 if input_api.platform == 'win32':
1467 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291468 checkperms_tool = input_api.os_path.join(
1469 input_api.PresubmitLocalPath(),
1470 'tools', 'checkperms', 'checkperms.py')
1471 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471472 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391473 with input_api.CreateTemporaryFile() as file_list:
1474 for f in input_api.AffectedFiles():
1475 # checkperms.py file/directory arguments must be relative to the
1476 # repository.
1477 file_list.write(f.LocalPath() + '\n')
1478 file_list.close()
1479 args += ['--file-list', file_list.name]
1480 try:
1481 input_api.subprocess.check_output(args)
1482 return []
1483 except input_api.subprocess.CalledProcessError as error:
1484 return [output_api.PresubmitError(
1485 'checkperms.py failed:',
1486 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221487
1488
robertocn832f5992017-01-04 19:01:301489def _CheckTeamTags(input_api, output_api):
1490 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1491 checkteamtags_tool = input_api.os_path.join(
1492 input_api.PresubmitLocalPath(),
1493 'tools', 'checkteamtags', 'checkteamtags.py')
1494 args = [input_api.python_executable, checkteamtags_tool,
1495 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221496 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301497 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1498 'OWNERS']
1499 try:
1500 if files:
1501 input_api.subprocess.check_output(args + files)
1502 return []
1503 except input_api.subprocess.CalledProcessError as error:
1504 return [output_api.PresubmitError(
1505 'checkteamtags.py failed:',
1506 long_text=error.output)]
1507
1508
[email protected]c8278b32012-10-30 20:35:491509def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1510 """Makes sure we don't include ui/aura/window_property.h
1511 in header files.
1512 """
1513 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1514 errors = []
1515 for f in input_api.AffectedFiles():
1516 if not f.LocalPath().endswith('.h'):
1517 continue
1518 for line_num, line in f.ChangedContents():
1519 if pattern.match(line):
1520 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1521
1522 results = []
1523 if errors:
1524 results.append(output_api.PresubmitError(
1525 'Header files should not include ui/aura/window_property.h', errors))
1526 return results
1527
1528
[email protected]70ca77752012-11-20 03:45:031529def _CheckForVersionControlConflictsInFile(input_api, f):
1530 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1531 errors = []
1532 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161533 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231534 # First-level headers in markdown look a lot like version control
1535 # conflict markers. http://daringfireball.net/projects/markdown/basics
1536 continue
[email protected]70ca77752012-11-20 03:45:031537 if pattern.match(line):
1538 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1539 return errors
1540
1541
1542def _CheckForVersionControlConflicts(input_api, output_api):
1543 """Usually this is not intentional and will cause a compile failure."""
1544 errors = []
1545 for f in input_api.AffectedFiles():
1546 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1547
1548 results = []
1549 if errors:
1550 results.append(output_api.PresubmitError(
1551 'Version control conflict markers found, please resolve.', errors))
1552 return results
1553
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201554
estadee17314a02017-01-12 16:22:161555def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1556 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1557 errors = []
1558 for f in input_api.AffectedFiles():
1559 for line_num, line in f.ChangedContents():
1560 if pattern.search(line):
1561 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1562
1563 results = []
1564 if errors:
1565 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501566 'Found Google support URL addressed by answer number. Please replace '
1567 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161568 return results
1569
[email protected]70ca77752012-11-20 03:45:031570
[email protected]06e6d0ff2012-12-11 01:36:441571def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1572 def FilterFile(affected_file):
1573 """Filter function for use with input_api.AffectedSourceFiles,
1574 below. This filters out everything except non-test files from
1575 top-level directories that generally speaking should not hard-code
1576 service URLs (e.g. src/android_webview/, src/content/ and others).
1577 """
1578 return input_api.FilterSourceFile(
1579 affected_file,
Egor Paskoce145c42018-09-28 19:31:041580 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441581 black_list=(_EXCLUDED_PATHS +
1582 _TEST_CODE_EXCLUDED_PATHS +
1583 input_api.DEFAULT_BLACK_LIST))
1584
reillyi38965732015-11-16 18:27:331585 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1586 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461587 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1588 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441589 problems = [] # items are (filename, line_number, line)
1590 for f in input_api.AffectedSourceFiles(FilterFile):
1591 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461592 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441593 problems.append((f.LocalPath(), line_num, line))
1594
1595 if problems:
[email protected]f7051d52013-04-02 18:31:421596 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441597 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581598 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441599 [' %s:%d: %s' % (
1600 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031601 else:
1602 return []
[email protected]06e6d0ff2012-12-11 01:36:441603
1604
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491605# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271606def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1607 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311608 The native_client_sdk directory is excluded because it has auto-generated PNG
1609 files for documentation.
[email protected]d2530012013-01-25 16:39:271610 """
[email protected]d2530012013-01-25 16:39:271611 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491612 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041613 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311614 file_filter = lambda f: input_api.FilterSourceFile(
1615 f, white_list=white_list, black_list=black_list)
1616 for f in input_api.AffectedFiles(include_deletes=False,
1617 file_filter=file_filter):
1618 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271619
1620 results = []
1621 if errors:
1622 results.append(output_api.PresubmitError(
1623 'The name of PNG files should not have abbreviations. \n'
1624 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1625 'Contact [email protected] if you have questions.', errors))
1626 return results
1627
1628
Daniel Cheng4dcdb6b2017-04-13 08:30:171629def _ExtractAddRulesFromParsedDeps(parsed_deps):
1630 """Extract the rules that add dependencies from a parsed DEPS file.
1631
1632 Args:
1633 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1634 add_rules = set()
1635 add_rules.update([
1636 rule[1:] for rule in parsed_deps.get('include_rules', [])
1637 if rule.startswith('+') or rule.startswith('!')
1638 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501639 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171640 {}).iteritems():
1641 add_rules.update([
1642 rule[1:] for rule in rules
1643 if rule.startswith('+') or rule.startswith('!')
1644 ])
1645 return add_rules
1646
1647
1648def _ParseDeps(contents):
1649 """Simple helper for parsing DEPS files."""
1650 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171651 class _VarImpl:
1652
1653 def __init__(self, local_scope):
1654 self._local_scope = local_scope
1655
1656 def Lookup(self, var_name):
1657 """Implements the Var syntax."""
1658 try:
1659 return self._local_scope['vars'][var_name]
1660 except KeyError:
1661 raise Exception('Var is not defined: %s' % var_name)
1662
1663 local_scope = {}
1664 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171665 'Var': _VarImpl(local_scope).Lookup,
1666 }
1667 exec contents in global_scope, local_scope
1668 return local_scope
1669
1670
1671def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081672 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411673 a set of DEPS entries that we should look up.
1674
1675 For a directory (rather than a specific filename) we fake a path to
1676 a specific filename by adding /DEPS. This is chosen as a file that
1677 will seldom or never be subject to per-file include_rules.
1678 """
[email protected]2b438d62013-11-14 17:54:141679 # We ignore deps entries on auto-generated directories.
1680 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081681
Daniel Cheng4dcdb6b2017-04-13 08:30:171682 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1683 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1684
1685 added_deps = new_deps.difference(old_deps)
1686
[email protected]2b438d62013-11-14 17:54:141687 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171688 for added_dep in added_deps:
1689 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1690 continue
1691 # Assume that a rule that ends in .h is a rule for a specific file.
1692 if added_dep.endswith('.h'):
1693 results.add(added_dep)
1694 else:
1695 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081696 return results
1697
1698
[email protected]e871964c2013-05-13 14:14:551699def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1700 """When a dependency prefixed with + is added to a DEPS file, we
1701 want to make sure that the change is reviewed by an OWNER of the
1702 target file or directory, to avoid layering violations from being
1703 introduced. This check verifies that this happens.
1704 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171705 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241706
1707 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491708 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241709 for f in input_api.AffectedFiles(include_deletes=False,
1710 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551711 filename = input_api.os_path.basename(f.LocalPath())
1712 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171713 virtual_depended_on_files.update(_CalculateAddedDeps(
1714 input_api.os_path,
1715 '\n'.join(f.OldContents()),
1716 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551717
[email protected]e871964c2013-05-13 14:14:551718 if not virtual_depended_on_files:
1719 return []
1720
1721 if input_api.is_committing:
1722 if input_api.tbr:
1723 return [output_api.PresubmitNotifyResult(
1724 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271725 if input_api.dry_run:
1726 return [output_api.PresubmitNotifyResult(
1727 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551728 if not input_api.change.issue:
1729 return [output_api.PresubmitError(
1730 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401731 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551732 output = output_api.PresubmitError
1733 else:
1734 output = output_api.PresubmitNotifyResult
1735
1736 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501737 owner_email, reviewers = (
1738 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1739 input_api,
1740 owners_db.email_regexp,
1741 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551742
1743 owner_email = owner_email or input_api.change.author_email
1744
[email protected]de4f7d22013-05-23 14:27:461745 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511746 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461747 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551748 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1749 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411750
1751 # We strip the /DEPS part that was added by
1752 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1753 # directory.
1754 def StripDeps(path):
1755 start_deps = path.rfind('/DEPS')
1756 if start_deps != -1:
1757 return path[:start_deps]
1758 else:
1759 return path
1760 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551761 for path in missing_files]
1762
1763 if unapproved_dependencies:
1764 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151765 output('You need LGTM from owners of depends-on paths in DEPS that were '
1766 'modified in this CL:\n %s' %
1767 '\n '.join(sorted(unapproved_dependencies)))]
1768 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1769 output_list.append(output(
1770 'Suggested missing target path OWNERS:\n %s' %
1771 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551772 return output_list
1773
1774 return []
1775
1776
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491777# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401778def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491779 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401780 black_list = (_EXCLUDED_PATHS +
1781 _TEST_CODE_EXCLUDED_PATHS +
1782 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041783 (r"^base[\\/]logging\.h$",
1784 r"^base[\\/]logging\.cc$",
1785 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1786 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1787 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121788 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:181789 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Egor Paskoce145c42018-09-28 19:31:041790 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1791 r"^chrome[\\/]chrome_cleaner[\\/].*",
1792 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031793 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041794 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1795 r"^chromecast[\\/]",
1796 r"^cloud_print[\\/]",
1797 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481798 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041799 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311800 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041801 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461802 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041803 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461804 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041805 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251806 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041807 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1808 r"^courgette[\\/]courgette_tool\.cc$",
1809 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271810 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331811 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041812 r"^ipc[\\/]ipc_logging\.cc$",
1813 r"^native_client_sdk[\\/]",
1814 r"^remoting[\\/]base[\\/]logging\.h$",
1815 r"^remoting[\\/]host[\\/].*",
1816 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331817 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1818 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041819 r"^tools[\\/]",
1820 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1821 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331822 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401823 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491824 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401825
thomasanderson625d3932017-03-29 07:16:581826 log_info = set([])
1827 printf = set([])
[email protected]85218562013-11-22 07:41:401828
1829 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581830 for _, line in f.ChangedContents():
1831 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1832 log_info.add(f.LocalPath())
1833 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1834 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371835
thomasanderson625d3932017-03-29 07:16:581836 if input_api.re.search(r"\bprintf\(", line):
1837 printf.add(f.LocalPath())
1838 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1839 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401840
1841 if log_info:
1842 return [output_api.PresubmitError(
1843 'These files spam the console log with LOG(INFO):',
1844 items=log_info)]
1845 if printf:
1846 return [output_api.PresubmitError(
1847 'These files spam the console log with printf/fprintf:',
1848 items=printf)]
1849 return []
1850
1851
[email protected]49aa76a2013-12-04 06:59:161852def _CheckForAnonymousVariables(input_api, output_api):
1853 """These types are all expected to hold locks while in scope and
1854 so should never be anonymous (which causes them to be immediately
1855 destroyed)."""
1856 they_who_must_be_named = [
1857 'base::AutoLock',
1858 'base::AutoReset',
1859 'base::AutoUnlock',
1860 'SkAutoAlphaRestore',
1861 'SkAutoBitmapShaderInstall',
1862 'SkAutoBlitterChoose',
1863 'SkAutoBounderCommit',
1864 'SkAutoCallProc',
1865 'SkAutoCanvasRestore',
1866 'SkAutoCommentBlock',
1867 'SkAutoDescriptor',
1868 'SkAutoDisableDirectionCheck',
1869 'SkAutoDisableOvalCheck',
1870 'SkAutoFree',
1871 'SkAutoGlyphCache',
1872 'SkAutoHDC',
1873 'SkAutoLockColors',
1874 'SkAutoLockPixels',
1875 'SkAutoMalloc',
1876 'SkAutoMaskFreeImage',
1877 'SkAutoMutexAcquire',
1878 'SkAutoPathBoundsUpdate',
1879 'SkAutoPDFRelease',
1880 'SkAutoRasterClipValidate',
1881 'SkAutoRef',
1882 'SkAutoTime',
1883 'SkAutoTrace',
1884 'SkAutoUnref',
1885 ]
1886 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1887 # bad: base::AutoLock(lock.get());
1888 # not bad: base::AutoLock lock(lock.get());
1889 bad_pattern = input_api.re.compile(anonymous)
1890 # good: new base::AutoLock(lock.get())
1891 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1892 errors = []
1893
1894 for f in input_api.AffectedFiles():
1895 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1896 continue
1897 for linenum, line in f.ChangedContents():
1898 if bad_pattern.search(line) and not good_pattern.search(line):
1899 errors.append('%s:%d' % (f.LocalPath(), linenum))
1900
1901 if errors:
1902 return [output_api.PresubmitError(
1903 'These lines create anonymous variables that need to be named:',
1904 items=errors)]
1905 return []
1906
1907
Peter Kasting4844e46e2018-02-23 07:27:101908def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531909 # Returns whether |template_str| is of the form <T, U...> for some types T
1910 # and U. Assumes that |template_str| is already in the form <...>.
1911 def HasMoreThanOneArg(template_str):
1912 # Level of <...> nesting.
1913 nesting = 0
1914 for c in template_str:
1915 if c == '<':
1916 nesting += 1
1917 elif c == '>':
1918 nesting -= 1
1919 elif c == ',' and nesting == 1:
1920 return True
1921 return False
1922
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491923 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101924 sources = lambda affected_file: input_api.FilterSourceFile(
1925 affected_file,
1926 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1927 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491928 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551929
1930 # Pattern to capture a single "<...>" block of template arguments. It can
1931 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1932 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1933 # latter would likely require counting that < and > match, which is not
1934 # expressible in regular languages. Should the need arise, one can introduce
1935 # limited counting (matching up to a total number of nesting depth), which
1936 # should cover all practical cases for already a low nesting limit.
1937 template_arg_pattern = (
1938 r'<[^>]*' # Opening block of <.
1939 r'>([^<]*>)?') # Closing block of >.
1940 # Prefix expressing that whatever follows is not already inside a <...>
1941 # block.
1942 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101943 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551944 not_inside_template_arg_pattern
1945 + r'\bstd::unique_ptr'
1946 + template_arg_pattern
1947 + r'\(\)')
1948
1949 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1950 template_arg_no_array_pattern = (
1951 r'<[^>]*[^]]' # Opening block of <.
1952 r'>([^(<]*[^]]>)?') # Closing block of >.
1953 # Prefix saying that what follows is the start of an expression.
1954 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1955 # Suffix saying that what follows are call parentheses with a non-empty list
1956 # of arguments.
1957 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531958 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551959 return_construct_pattern = input_api.re.compile(
1960 start_of_expr_pattern
1961 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531962 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551963 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531964 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551965 + nonempty_arg_list_pattern)
1966
Vaclav Brozek851d9602018-04-04 16:13:051967 problems_constructor = []
1968 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101969 for f in input_api.AffectedSourceFiles(sources):
1970 for line_number, line in f.ChangedContents():
1971 # Disallow:
1972 # return std::unique_ptr<T>(foo);
1973 # bar = std::unique_ptr<T>(foo);
1974 # But allow:
1975 # return std::unique_ptr<T[]>(foo);
1976 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531977 # And also allow cases when the second template argument is present. Those
1978 # cases cannot be handled by std::make_unique:
1979 # return std::unique_ptr<T, U>(foo);
1980 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051981 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531982 return_construct_result = return_construct_pattern.search(line)
1983 if return_construct_result and not HasMoreThanOneArg(
1984 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051985 problems_constructor.append(
1986 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101987 # Disallow:
1988 # std::unique_ptr<T>()
1989 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051990 problems_nullptr.append(
1991 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1992
1993 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161994 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051995 errors.append(output_api.PresubmitError(
1996 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161997 problems_nullptr))
1998 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051999 errors.append(output_api.PresubmitError(
2000 'The following files use explicit std::unique_ptr constructor.'
2001 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162002 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102003 return errors
2004
2005
[email protected]999261d2014-03-03 20:08:082006def _CheckUserActionUpdate(input_api, output_api):
2007 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522008 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082009 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522010 # If actions.xml is already included in the changelist, the PRESUBMIT
2011 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082012 return []
2013
[email protected]999261d2014-03-03 20:08:082014 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2015 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522016 current_actions = None
[email protected]999261d2014-03-03 20:08:082017 for f in input_api.AffectedFiles(file_filter=file_filter):
2018 for line_num, line in f.ChangedContents():
2019 match = input_api.re.search(action_re, line)
2020 if match:
[email protected]2f92dec2014-03-07 19:21:522021 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2022 # loaded only once.
2023 if not current_actions:
2024 with open('tools/metrics/actions/actions.xml') as actions_f:
2025 current_actions = actions_f.read()
2026 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082027 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522028 action = 'name="{0}"'.format(action_name)
2029 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082030 return [output_api.PresubmitPromptWarning(
2031 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522032 'tools/metrics/actions/actions.xml. Please run '
2033 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082034 % (f.LocalPath(), line_num, action_name))]
2035 return []
2036
2037
Daniel Cheng13ca61a882017-08-25 15:11:252038def _ImportJSONCommentEater(input_api):
2039 import sys
2040 sys.path = sys.path + [input_api.os_path.join(
2041 input_api.PresubmitLocalPath(),
2042 'tools', 'json_comment_eater')]
2043 import json_comment_eater
2044 return json_comment_eater
2045
2046
[email protected]99171a92014-06-03 08:44:472047def _GetJSONParseError(input_api, filename, eat_comments=True):
2048 try:
2049 contents = input_api.ReadFile(filename)
2050 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252051 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132052 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472053
2054 input_api.json.loads(contents)
2055 except ValueError as e:
2056 return e
2057 return None
2058
2059
2060def _GetIDLParseError(input_api, filename):
2061 try:
2062 contents = input_api.ReadFile(filename)
2063 idl_schema = input_api.os_path.join(
2064 input_api.PresubmitLocalPath(),
2065 'tools', 'json_schema_compiler', 'idl_schema.py')
2066 process = input_api.subprocess.Popen(
2067 [input_api.python_executable, idl_schema],
2068 stdin=input_api.subprocess.PIPE,
2069 stdout=input_api.subprocess.PIPE,
2070 stderr=input_api.subprocess.PIPE,
2071 universal_newlines=True)
2072 (_, error) = process.communicate(input=contents)
2073 return error or None
2074 except ValueError as e:
2075 return e
2076
2077
2078def _CheckParseErrors(input_api, output_api):
2079 """Check that IDL and JSON files do not contain syntax errors."""
2080 actions = {
2081 '.idl': _GetIDLParseError,
2082 '.json': _GetJSONParseError,
2083 }
[email protected]99171a92014-06-03 08:44:472084 # Most JSON files are preprocessed and support comments, but these do not.
2085 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042086 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472087 ]
2088 # Only run IDL checker on files in these directories.
2089 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042090 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2091 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472092 ]
2093
2094 def get_action(affected_file):
2095 filename = affected_file.LocalPath()
2096 return actions.get(input_api.os_path.splitext(filename)[1])
2097
[email protected]99171a92014-06-03 08:44:472098 def FilterFile(affected_file):
2099 action = get_action(affected_file)
2100 if not action:
2101 return False
2102 path = affected_file.LocalPath()
2103
Sean Kau46e29bc2017-08-28 16:31:162104 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472105 return False
2106
2107 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162108 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472109 return False
2110 return True
2111
2112 results = []
2113 for affected_file in input_api.AffectedFiles(
2114 file_filter=FilterFile, include_deletes=False):
2115 action = get_action(affected_file)
2116 kwargs = {}
2117 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162118 _MatchesFile(input_api, json_no_comments_patterns,
2119 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472120 kwargs['eat_comments'] = False
2121 parse_error = action(input_api,
2122 affected_file.AbsoluteLocalPath(),
2123 **kwargs)
2124 if parse_error:
2125 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2126 (affected_file.LocalPath(), parse_error)))
2127 return results
2128
2129
[email protected]760deea2013-12-10 19:33:492130def _CheckJavaStyle(input_api, output_api):
2131 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472132 import sys
[email protected]760deea2013-12-10 19:33:492133 original_sys_path = sys.path
2134 try:
2135 sys.path = sys.path + [input_api.os_path.join(
2136 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2137 import checkstyle
2138 finally:
2139 # Restore sys.path to what it was before.
2140 sys.path = original_sys_path
2141
2142 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092143 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512144 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492145
2146
Sean Kau46e29bc2017-08-28 16:31:162147def _MatchesFile(input_api, patterns, path):
2148 for pattern in patterns:
2149 if input_api.re.search(pattern, path):
2150 return True
2151 return False
2152
2153
Daniel Cheng7052cdf2017-11-21 19:23:292154def _GetOwnersFilesToCheckForIpcOwners(input_api):
2155 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172156
Daniel Cheng7052cdf2017-11-21 19:23:292157 Returns:
2158 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2159 contain to cover IPC-related files with noparent reviewer rules.
2160 """
2161 # Whether or not a file affects IPC is (mostly) determined by a simple list
2162 # of filename patterns.
dchenge07de812016-06-20 19:27:172163 file_patterns = [
palmerb19a0932017-01-24 04:00:312164 # Legacy IPC:
dchenge07de812016-06-20 19:27:172165 '*_messages.cc',
2166 '*_messages*.h',
2167 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312168 # Mojo IPC:
dchenge07de812016-06-20 19:27:172169 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472170 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172171 '*_struct_traits*.*',
2172 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312173 '*.typemap',
2174 # Android native IPC:
2175 '*.aidl',
2176 # Blink uses a different file naming convention:
2177 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472178 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172179 '*StructTraits*.*',
2180 '*TypeConverter*.*',
2181 ]
2182
scottmg7a6ed5ba2016-11-04 18:22:042183 # These third_party directories do not contain IPCs, but contain files
2184 # matching the above patterns, which trigger false positives.
2185 exclude_paths = [
2186 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232187 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062188 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292189 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042190 ]
2191
dchenge07de812016-06-20 19:27:172192 # Dictionary mapping an OWNERS file path to Patterns.
2193 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2194 # rules ) to a PatternEntry.
2195 # PatternEntry is a dictionary with two keys:
2196 # - 'files': the files that are matched by this pattern
2197 # - 'rules': the per-file rules needed for this pattern
2198 # For example, if we expect OWNERS file to contain rules for *.mojom and
2199 # *_struct_traits*.*, Patterns might look like this:
2200 # {
2201 # '*.mojom': {
2202 # 'files': ...,
2203 # 'rules': [
2204 # 'per-file *.mojom=set noparent',
2205 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2206 # ],
2207 # },
2208 # '*_struct_traits*.*': {
2209 # 'files': ...,
2210 # 'rules': [
2211 # 'per-file *_struct_traits*.*=set noparent',
2212 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2213 # ],
2214 # },
2215 # }
2216 to_check = {}
2217
Daniel Cheng13ca61a882017-08-25 15:11:252218 def AddPatternToCheck(input_file, pattern):
2219 owners_file = input_api.os_path.join(
2220 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2221 if owners_file not in to_check:
2222 to_check[owners_file] = {}
2223 if pattern not in to_check[owners_file]:
2224 to_check[owners_file][pattern] = {
2225 'files': [],
2226 'rules': [
2227 'per-file %s=set noparent' % pattern,
2228 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2229 ]
2230 }
Vaclav Brozekd5de76a2018-03-17 07:57:502231 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252232
dchenge07de812016-06-20 19:27:172233 # Iterate through the affected files to see what we actually need to check
2234 # for. We should only nag patch authors about per-file rules if a file in that
2235 # directory would match that pattern. If a directory only contains *.mojom
2236 # files and no *_messages*.h files, we should only nag about rules for
2237 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252238 for f in input_api.AffectedFiles(include_deletes=False):
2239 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362240 # affected files for .json, .cc, and .h files which look like they contain
2241 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162242 if (f.LocalPath().endswith('.json') and
2243 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2244 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252245 json_comment_eater = _ImportJSONCommentEater(input_api)
2246 mostly_json_lines = '\n'.join(f.NewContents())
2247 # Comments aren't allowed in strict JSON, so filter them out.
2248 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432249 try:
2250 json_content = input_api.json.loads(json_lines)
2251 except:
2252 # There's another PRESUBMIT check that already verifies that JSON files
2253 # are not invalid, so no need to emit another warning here.
2254 continue
Daniel Cheng13ca61a882017-08-25 15:11:252255 if 'interface_provider_specs' in json_content:
2256 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362257 else:
2258 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2259 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2260 if (manifest_pattern.search(f.LocalPath()) and not
2261 test_manifest_pattern.search(f.LocalPath())):
2262 # We expect all actual service manifest files to contain at least one
2263 # qualified reference to service_manager::Manifest.
2264 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2265 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172266 for pattern in file_patterns:
2267 if input_api.fnmatch.fnmatch(
2268 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042269 skip = False
2270 for exclude in exclude_paths:
2271 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2272 skip = True
2273 break
2274 if skip:
2275 continue
Daniel Cheng13ca61a882017-08-25 15:11:252276 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172277 break
2278
Daniel Cheng7052cdf2017-11-21 19:23:292279 return to_check
2280
2281
2282def _CheckIpcOwners(input_api, output_api):
2283 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2284 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2285
2286 if to_check:
2287 # If there are any OWNERS files to check, there are IPC-related changes in
2288 # this CL. Auto-CC the review list.
2289 output_api.AppendCC('[email protected]')
2290
2291 # Go through the OWNERS files to check, filtering out rules that are already
2292 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172293 for owners_file, patterns in to_check.iteritems():
2294 try:
2295 with file(owners_file) as f:
2296 lines = set(f.read().splitlines())
2297 for entry in patterns.itervalues():
2298 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2299 ]
2300 except IOError:
2301 # No OWNERS file, so all the rules are definitely missing.
2302 continue
2303
2304 # All the remaining lines weren't found in OWNERS files, so emit an error.
2305 errors = []
2306 for owners_file, patterns in to_check.iteritems():
2307 missing_lines = []
2308 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502309 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172310 missing_lines.extend(entry['rules'])
2311 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2312 if missing_lines:
2313 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052314 'Because of the presence of files:\n%s\n\n'
2315 '%s needs the following %d lines added:\n\n%s' %
2316 ('\n'.join(files), owners_file, len(missing_lines),
2317 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172318
2319 results = []
2320 if errors:
vabrf5ce3bf92016-07-11 14:52:412321 if input_api.is_committing:
2322 output = output_api.PresubmitError
2323 else:
2324 output = output_api.PresubmitPromptWarning
2325 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592326 'Found OWNERS files that need to be updated for IPC security ' +
2327 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172328 long_text='\n\n'.join(errors)))
2329
2330 return results
2331
2332
jbriance9e12f162016-11-25 07:57:502333def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312334 """Checks that added or removed lines in non third party affected
2335 header files do not lead to new useless class or struct forward
2336 declaration.
jbriance9e12f162016-11-25 07:57:502337 """
2338 results = []
2339 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2340 input_api.re.MULTILINE)
2341 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2342 input_api.re.MULTILINE)
2343 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312344 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192345 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492346 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312347 continue
2348
jbriance9e12f162016-11-25 07:57:502349 if not f.LocalPath().endswith('.h'):
2350 continue
2351
2352 contents = input_api.ReadFile(f)
2353 fwd_decls = input_api.re.findall(class_pattern, contents)
2354 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2355
2356 useless_fwd_decls = []
2357 for decl in fwd_decls:
2358 count = sum(1 for _ in input_api.re.finditer(
2359 r'\b%s\b' % input_api.re.escape(decl), contents))
2360 if count == 1:
2361 useless_fwd_decls.append(decl)
2362
2363 if not useless_fwd_decls:
2364 continue
2365
2366 for line in f.GenerateScmDiff().splitlines():
2367 if (line.startswith('-') and not line.startswith('--') or
2368 line.startswith('+') and not line.startswith('++')):
2369 for decl in useless_fwd_decls:
2370 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2371 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242372 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502373 (f.LocalPath(), decl)))
2374 useless_fwd_decls.remove(decl)
2375
2376 return results
2377
Jinsong Fan91ebbbd2019-04-16 14:57:172378def _CheckAndroidDebuggableBuild(input_api, output_api):
2379 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2380 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2381 this is a debuggable build of Android.
2382 """
2383 build_type_check_pattern = input_api.re.compile(
2384 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2385
2386 errors = []
2387
2388 sources = lambda affected_file: input_api.FilterSourceFile(
2389 affected_file,
2390 black_list=(_EXCLUDED_PATHS +
2391 _TEST_CODE_EXCLUDED_PATHS +
2392 input_api.DEFAULT_BLACK_LIST +
2393 (r"^android_webview[\\/]support_library[\\/]"
2394 "boundary_interfaces[\\/]",
2395 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2396 r'^third_party[\\/].*',
2397 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2398 r"webview[\\/]chromium[\\/]License.*",)),
2399 white_list=[r'.*\.java$'])
2400
2401 for f in input_api.AffectedSourceFiles(sources):
2402 for line_num, line in f.ChangedContents():
2403 if build_type_check_pattern.search(line):
2404 errors.append("%s:%d" % (f.LocalPath(), line_num))
2405
2406 results = []
2407
2408 if errors:
2409 results.append(output_api.PresubmitPromptWarning(
2410 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2411 ' Please use BuildInfo.isDebugAndroid() instead.',
2412 errors))
2413
2414 return results
jbriance9e12f162016-11-25 07:57:502415
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492416# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292417def _CheckAndroidToastUsage(input_api, output_api):
2418 """Checks that code uses org.chromium.ui.widget.Toast instead of
2419 android.widget.Toast (Chromium Toast doesn't force hardware
2420 acceleration on low-end devices, saving memory).
2421 """
2422 toast_import_pattern = input_api.re.compile(
2423 r'^import android\.widget\.Toast;$')
2424
2425 errors = []
2426
2427 sources = lambda affected_file: input_api.FilterSourceFile(
2428 affected_file,
2429 black_list=(_EXCLUDED_PATHS +
2430 _TEST_CODE_EXCLUDED_PATHS +
2431 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042432 (r'^chromecast[\\/].*',
2433 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492434 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292435
2436 for f in input_api.AffectedSourceFiles(sources):
2437 for line_num, line in f.ChangedContents():
2438 if toast_import_pattern.search(line):
2439 errors.append("%s:%d" % (f.LocalPath(), line_num))
2440
2441 results = []
2442
2443 if errors:
2444 results.append(output_api.PresubmitError(
2445 'android.widget.Toast usage is detected. Android toasts use hardware'
2446 ' acceleration, and can be\ncostly on low-end devices. Please use'
2447 ' org.chromium.ui.widget.Toast instead.\n'
2448 'Contact [email protected] if you have any questions.',
2449 errors))
2450
2451 return results
2452
2453
dgnaa68d5e2015-06-10 10:08:222454def _CheckAndroidCrLogUsage(input_api, output_api):
2455 """Checks that new logs using org.chromium.base.Log:
2456 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512457 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222458 """
pkotwicza1dd0b002016-05-16 14:41:042459
torne89540622017-03-24 19:41:302460 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042461 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302462 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042463 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302464 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042465 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2466 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092467 # The customtabs_benchmark is a small app that does not depend on Chromium
2468 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042469 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042470 ]
2471
dgnaa68d5e2015-06-10 10:08:222472 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122473 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2474 class_in_base_pattern = input_api.re.compile(
2475 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2476 has_some_log_import_pattern = input_api.re.compile(
2477 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222478 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122479 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222480 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512481 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222482 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222483
Vincent Scheib16d7b272015-09-15 18:09:072484 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222485 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492486 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042487 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122488
dgnaa68d5e2015-06-10 10:08:222489 tag_decl_errors = []
2490 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122491 tag_errors = []
dgn38736db2015-09-18 19:20:512492 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122493 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222494
2495 for f in input_api.AffectedSourceFiles(sources):
2496 file_content = input_api.ReadFile(f)
2497 has_modified_logs = False
2498
2499 # Per line checks
dgn87d9fb62015-06-12 09:15:122500 if (cr_log_import_pattern.search(file_content) or
2501 (class_in_base_pattern.search(file_content) and
2502 not has_some_log_import_pattern.search(file_content))):
2503 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222504 for line_num, line in f.ChangedContents():
2505
2506 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122507 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222508 if match:
2509 has_modified_logs = True
2510
2511 # Make sure it uses "TAG"
2512 if not match.group('tag') == 'TAG':
2513 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122514 else:
2515 # Report non cr Log function calls in changed lines
2516 for line_num, line in f.ChangedContents():
2517 if log_call_pattern.search(line):
2518 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222519
2520 # Per file checks
2521 if has_modified_logs:
2522 # Make sure the tag is using the "cr" prefix and is not too long
2523 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512524 tag_name = match.group('name') if match else None
2525 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222526 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512527 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222528 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512529 elif '.' in tag_name:
2530 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222531
2532 results = []
2533 if tag_decl_errors:
2534 results.append(output_api.PresubmitPromptWarning(
2535 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512536 '"private static final String TAG = "<package tag>".\n'
2537 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222538 tag_decl_errors))
2539
2540 if tag_length_errors:
2541 results.append(output_api.PresubmitError(
2542 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512543 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222544 tag_length_errors))
2545
2546 if tag_errors:
2547 results.append(output_api.PresubmitPromptWarning(
2548 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2549 tag_errors))
2550
dgn87d9fb62015-06-12 09:15:122551 if util_log_errors:
dgn4401aa52015-04-29 16:26:172552 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122553 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2554 util_log_errors))
2555
dgn38736db2015-09-18 19:20:512556 if tag_with_dot_errors:
2557 results.append(output_api.PresubmitPromptWarning(
2558 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2559 tag_with_dot_errors))
2560
dgn4401aa52015-04-29 16:26:172561 return results
2562
2563
Yoland Yanb92fa522017-08-28 17:37:062564def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2565 """Checks that junit.framework.* is no longer used."""
2566 deprecated_junit_framework_pattern = input_api.re.compile(
2567 r'^import junit\.framework\..*;',
2568 input_api.re.MULTILINE)
2569 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492570 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062571 errors = []
2572 for f in input_api.AffectedFiles(sources):
2573 for line_num, line in f.ChangedContents():
2574 if deprecated_junit_framework_pattern.search(line):
2575 errors.append("%s:%d" % (f.LocalPath(), line_num))
2576
2577 results = []
2578 if errors:
2579 results.append(output_api.PresubmitError(
2580 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2581 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2582 ' if you have any question.', errors))
2583 return results
2584
2585
2586def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2587 """Checks that if new Java test classes have inheritance.
2588 Either the new test class is JUnit3 test or it is a JUnit4 test class
2589 with a base class, either case is undesirable.
2590 """
2591 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2592
2593 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492594 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062595 errors = []
2596 for f in input_api.AffectedFiles(sources):
2597 if not f.OldContents():
2598 class_declaration_start_flag = False
2599 for line_num, line in f.ChangedContents():
2600 if class_declaration_pattern.search(line):
2601 class_declaration_start_flag = True
2602 if class_declaration_start_flag and ' extends ' in line:
2603 errors.append('%s:%d' % (f.LocalPath(), line_num))
2604 if '{' in line:
2605 class_declaration_start_flag = False
2606
2607 results = []
2608 if errors:
2609 results.append(output_api.PresubmitPromptWarning(
2610 'The newly created files include Test classes that inherits from base'
2611 ' class. Please do not use inheritance in JUnit4 tests or add new'
2612 ' JUnit3 tests. Contact [email protected] if you have any'
2613 ' questions.', errors))
2614 return results
2615
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202616
yolandyan45001472016-12-21 21:12:422617def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2618 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2619 deprecated_annotation_import_pattern = input_api.re.compile(
2620 r'^import android\.test\.suitebuilder\.annotation\..*;',
2621 input_api.re.MULTILINE)
2622 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492623 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422624 errors = []
2625 for f in input_api.AffectedFiles(sources):
2626 for line_num, line in f.ChangedContents():
2627 if deprecated_annotation_import_pattern.search(line):
2628 errors.append("%s:%d" % (f.LocalPath(), line_num))
2629
2630 results = []
2631 if errors:
2632 results.append(output_api.PresubmitError(
2633 'Annotations in android.test.suitebuilder.annotation have been'
2634 ' deprecated since API level 24. Please use android.support.test.filters'
2635 ' from //third_party/android_support_test_runner:runner_java instead.'
2636 ' Contact [email protected] if you have any questions.', errors))
2637 return results
2638
2639
agrieve7b6479d82015-10-07 14:24:222640def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2641 """Checks if MDPI assets are placed in a correct directory."""
2642 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2643 ('/res/drawable/' in f.LocalPath() or
2644 '/res/drawable-ldrtl/' in f.LocalPath()))
2645 errors = []
2646 for f in input_api.AffectedFiles(include_deletes=False,
2647 file_filter=file_filter):
2648 errors.append(' %s' % f.LocalPath())
2649
2650 results = []
2651 if errors:
2652 results.append(output_api.PresubmitError(
2653 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2654 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2655 '/res/drawable-ldrtl/.\n'
2656 'Contact [email protected] if you have questions.', errors))
2657 return results
2658
2659
Nate Fischer535972b2017-09-16 01:06:182660def _CheckAndroidWebkitImports(input_api, output_api):
2661 """Checks that code uses org.chromium.base.Callback instead of
2662 android.widget.ValueCallback except in the WebView glue layer.
2663 """
2664 valuecallback_import_pattern = input_api.re.compile(
2665 r'^import android\.webkit\.ValueCallback;$')
2666
2667 errors = []
2668
2669 sources = lambda affected_file: input_api.FilterSourceFile(
2670 affected_file,
2671 black_list=(_EXCLUDED_PATHS +
2672 _TEST_CODE_EXCLUDED_PATHS +
2673 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042674 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492675 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182676
2677 for f in input_api.AffectedSourceFiles(sources):
2678 for line_num, line in f.ChangedContents():
2679 if valuecallback_import_pattern.search(line):
2680 errors.append("%s:%d" % (f.LocalPath(), line_num))
2681
2682 results = []
2683
2684 if errors:
2685 results.append(output_api.PresubmitError(
2686 'android.webkit.ValueCallback usage is detected outside of the glue'
2687 ' layer. To stay compatible with the support library, android.webkit.*'
2688 ' classes should only be used inside the glue layer and'
2689 ' org.chromium.base.Callback should be used instead.',
2690 errors))
2691
2692 return results
2693
2694
Becky Zhou7c69b50992018-12-10 19:37:572695def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2696 """Checks Android XML styles """
2697 import sys
2698 original_sys_path = sys.path
2699 try:
2700 sys.path = sys.path + [input_api.os_path.join(
2701 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2702 import checkxmlstyle
2703 finally:
2704 # Restore sys.path to what it was before.
2705 sys.path = original_sys_path
2706
2707 if is_check_on_upload:
2708 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2709 else:
2710 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2711
2712
agrievef32bcc72016-04-04 14:57:402713class PydepsChecker(object):
2714 def __init__(self, input_api, pydeps_files):
2715 self._file_cache = {}
2716 self._input_api = input_api
2717 self._pydeps_files = pydeps_files
2718
2719 def _LoadFile(self, path):
2720 """Returns the list of paths within a .pydeps file relative to //."""
2721 if path not in self._file_cache:
2722 with open(path) as f:
2723 self._file_cache[path] = f.read()
2724 return self._file_cache[path]
2725
2726 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2727 """Returns an interable of paths within the .pydep, relativized to //."""
2728 os_path = self._input_api.os_path
2729 pydeps_dir = os_path.dirname(pydeps_path)
2730 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2731 if not l.startswith('*'))
2732 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2733
2734 def _CreateFilesToPydepsMap(self):
2735 """Returns a map of local_path -> list_of_pydeps."""
2736 ret = {}
2737 for pydep_local_path in self._pydeps_files:
2738 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2739 ret.setdefault(path, []).append(pydep_local_path)
2740 return ret
2741
2742 def ComputeAffectedPydeps(self):
2743 """Returns an iterable of .pydeps files that might need regenerating."""
2744 affected_pydeps = set()
2745 file_to_pydeps_map = None
2746 for f in self._input_api.AffectedFiles(include_deletes=True):
2747 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:462748 # Changes to DEPS can lead to .pydeps changes if any .py files are in
2749 # subrepositories. We can't figure out which files change, so re-check
2750 # all files.
2751 # Changes to print_python_deps.py affect all .pydeps.
2752 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:402753 return self._pydeps_files
2754 elif local_path.endswith('.pydeps'):
2755 if local_path in self._pydeps_files:
2756 affected_pydeps.add(local_path)
2757 elif local_path.endswith('.py'):
2758 if file_to_pydeps_map is None:
2759 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2760 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2761 return affected_pydeps
2762
2763 def DetermineIfStale(self, pydeps_path):
2764 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412765 import difflib
John Budorick47ca3fe2018-02-10 00:53:102766 import os
2767
agrievef32bcc72016-04-04 14:57:402768 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2769 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102770 env = dict(os.environ)
2771 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402772 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102773 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412774 old_contents = old_pydeps_data[2:]
2775 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402776 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412777 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402778
2779
2780def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2781 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402782 # This check is for Python dependency lists (.pydeps files), and involves
2783 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2784 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282785 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002786 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022787 # TODO(agrieve): Update when there's a better way to detect
2788 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402789 is_android = input_api.os_path.exists('third_party/android_tools')
2790 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2791 results = []
2792 # First, check for new / deleted .pydeps.
2793 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032794 # Check whether we are running the presubmit check for a file in src.
2795 # f.LocalPath is relative to repo (src, or internal repo).
2796 # os_path.exists is relative to src repo.
2797 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2798 # to src and we can conclude that the pydeps is in src.
2799 if input_api.os_path.exists(f.LocalPath()):
2800 if f.LocalPath().endswith('.pydeps'):
2801 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2802 results.append(output_api.PresubmitError(
2803 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2804 'remove %s' % f.LocalPath()))
2805 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2806 results.append(output_api.PresubmitError(
2807 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2808 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402809
2810 if results:
2811 return results
2812
2813 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2814
2815 for pydep_path in checker.ComputeAffectedPydeps():
2816 try:
phajdan.jr0d9878552016-11-04 10:49:412817 result = checker.DetermineIfStale(pydep_path)
2818 if result:
2819 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402820 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412821 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2822 'To regenerate, run:\n\n %s' %
2823 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402824 except input_api.subprocess.CalledProcessError as error:
2825 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2826 long_text=error.output)]
2827
2828 return results
2829
2830
glidere61efad2015-02-18 17:39:432831def _CheckSingletonInHeaders(input_api, output_api):
2832 """Checks to make sure no header files have |Singleton<|."""
2833 def FileFilter(affected_file):
2834 # It's ok for base/memory/singleton.h to have |Singleton<|.
2835 black_list = (_EXCLUDED_PATHS +
2836 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042837 (r"^base[\\/]memory[\\/]singleton\.h$",
2838 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472839 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432840 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2841
sergeyu34d21222015-09-16 00:11:442842 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432843 files = []
2844 for f in input_api.AffectedSourceFiles(FileFilter):
2845 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2846 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2847 contents = input_api.ReadFile(f)
2848 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242849 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432850 pattern.search(line)):
2851 files.append(f)
2852 break
2853
2854 if files:
yolandyandaabc6d2016-04-18 18:29:392855 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442856 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432857 'Please move them to an appropriate source file so that the ' +
2858 'template gets instantiated in a single compilation unit.',
2859 files) ]
2860 return []
2861
2862
[email protected]fd20b902014-05-09 02:14:532863_DEPRECATED_CSS = [
2864 # Values
2865 ( "-webkit-box", "flex" ),
2866 ( "-webkit-inline-box", "inline-flex" ),
2867 ( "-webkit-flex", "flex" ),
2868 ( "-webkit-inline-flex", "inline-flex" ),
2869 ( "-webkit-min-content", "min-content" ),
2870 ( "-webkit-max-content", "max-content" ),
2871
2872 # Properties
2873 ( "-webkit-background-clip", "background-clip" ),
2874 ( "-webkit-background-origin", "background-origin" ),
2875 ( "-webkit-background-size", "background-size" ),
2876 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442877 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532878
2879 # Functions
2880 ( "-webkit-gradient", "gradient" ),
2881 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2882 ( "-webkit-linear-gradient", "linear-gradient" ),
2883 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2884 ( "-webkit-radial-gradient", "radial-gradient" ),
2885 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2886]
2887
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202888
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492889# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242890def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532891 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252892 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342893 documentation and iOS CSS for dom distiller
2894 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252895 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532896 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492897 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252898 black_list = (_EXCLUDED_PATHS +
2899 _TEST_CODE_EXCLUDED_PATHS +
2900 input_api.DEFAULT_BLACK_LIST +
2901 (r"^chrome/common/extensions/docs",
2902 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342903 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442904 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252905 r"^native_client_sdk"))
2906 file_filter = lambda f: input_api.FilterSourceFile(
2907 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532908 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2909 for line_num, line in fpath.ChangedContents():
2910 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022911 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532912 results.append(output_api.PresubmitError(
2913 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2914 (fpath.LocalPath(), line_num, deprecated_value, value)))
2915 return results
2916
mohan.reddyf21db962014-10-16 12:26:472917
dbeam070cfe62014-10-22 06:44:022918_DEPRECATED_JS = [
2919 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2920 ( "__defineGetter__", "Object.defineProperty" ),
2921 ( "__defineSetter__", "Object.defineProperty" ),
2922]
2923
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202924
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492925# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242926def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022927 """Make sure that we don't use deprecated JS in Chrome code."""
2928 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492929 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022930 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2931 input_api.DEFAULT_BLACK_LIST)
2932 file_filter = lambda f: input_api.FilterSourceFile(
2933 f, white_list=file_inclusion_pattern, black_list=black_list)
2934 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2935 for lnum, line in fpath.ChangedContents():
2936 for (deprecated, replacement) in _DEPRECATED_JS:
2937 if deprecated in line:
2938 results.append(output_api.PresubmitError(
2939 "%s:%d: Use of deprecated JS %s, use %s instead" %
2940 (fpath.LocalPath(), lnum, deprecated, replacement)))
2941 return results
2942
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202943
rlanday6802cf632017-05-30 17:48:362944def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:362945 bad_files = {}
2946 for f in input_api.AffectedFiles(include_deletes=False):
2947 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492948 not f.LocalPath().startswith('third_party/blink') and
2949 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362950 continue
2951
Daniel Bratell65b033262019-04-23 08:17:062952 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:362953 continue
2954
Vaclav Brozekd5de76a2018-03-17 07:57:502955 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362956 if "#include" in line and "../" in line]
2957 if not relative_includes:
2958 continue
2959 bad_files[f.LocalPath()] = relative_includes
2960
2961 if not bad_files:
2962 return []
2963
2964 error_descriptions = []
2965 for file_path, bad_lines in bad_files.iteritems():
2966 error_description = file_path
2967 for line in bad_lines:
2968 error_description += '\n ' + line
2969 error_descriptions.append(error_description)
2970
2971 results = []
2972 results.append(output_api.PresubmitError(
2973 'You added one or more relative #include paths (including "../").\n'
2974 'These shouldn\'t be used because they can be used to include headers\n'
2975 'from code that\'s not correctly specified as a dependency in the\n'
2976 'relevant BUILD.gn file(s).',
2977 error_descriptions))
2978
2979 return results
2980
Takeshi Yoshinoe387aa32017-08-02 13:16:132981
Daniel Bratell65b033262019-04-23 08:17:062982def _CheckForCcIncludes(input_api, output_api):
2983 """Check that nobody tries to include a cc file. It's a relatively
2984 common error which results in duplicate symbols in object
2985 files. This may not always break the build until someone later gets
2986 very confusing linking errors."""
2987 results = []
2988 for f in input_api.AffectedFiles(include_deletes=False):
2989 # We let third_party code do whatever it wants
2990 if (f.LocalPath().startswith('third_party') and
2991 not f.LocalPath().startswith('third_party/blink') and
2992 not f.LocalPath().startswith('third_party\\blink')):
2993 continue
2994
2995 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
2996 continue
2997
2998 for _, line in f.ChangedContents():
2999 if line.startswith('#include "'):
3000 included_file = line.split('"')[1]
3001 if _IsCPlusPlusFile(input_api, included_file):
3002 # The most common naming for external files with C++ code,
3003 # apart from standard headers, is to call them foo.inc, but
3004 # Chromium sometimes uses foo-inc.cc so allow that as well.
3005 if not included_file.endswith(('.h', '-inc.cc')):
3006 results.append(output_api.PresubmitError(
3007 'Only header files or .inc files should be included in other\n'
3008 'C++ files. Compiling the contents of a cc file more than once\n'
3009 'will cause duplicate information in the build which may later\n'
3010 'result in strange link_errors.\n' +
3011 f.LocalPath() + ':\n ' +
3012 line))
3013
3014 return results
3015
3016
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203017def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3018 if not isinstance(key, ast.Str):
3019 return 'Key at line %d must be a string literal' % key.lineno
3020 if not isinstance(value, ast.Dict):
3021 return 'Value at line %d must be a dict' % value.lineno
3022 if len(value.keys) != 1:
3023 return 'Dict at line %d must have single entry' % value.lineno
3024 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3025 return (
3026 'Entry at line %d must have a string literal \'filepath\' as key' %
3027 value.lineno)
3028 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133029
Takeshi Yoshinoe387aa32017-08-02 13:16:133030
Sergey Ulanov4af16052018-11-08 02:41:463031def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203032 if not isinstance(key, ast.Str):
3033 return 'Key at line %d must be a string literal' % key.lineno
3034 if not isinstance(value, ast.List):
3035 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463036 for element in value.elts:
3037 if not isinstance(element, ast.Str):
3038 return 'Watchlist elements on line %d is not a string' % key.lineno
3039 if not email_regex.match(element.s):
3040 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3041 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203042 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133043
Takeshi Yoshinoe387aa32017-08-02 13:16:133044
Sergey Ulanov4af16052018-11-08 02:41:463045def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203046 mismatch_template = (
3047 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3048 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133049
Sergey Ulanov4af16052018-11-08 02:41:463050 email_regex = input_api.re.compile(
3051 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3052
3053 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203054 i = 0
3055 last_key = ''
3056 while True:
3057 if i >= len(wd_dict.keys):
3058 if i >= len(w_dict.keys):
3059 return None
3060 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3061 elif i >= len(w_dict.keys):
3062 return (
3063 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133064
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203065 wd_key = wd_dict.keys[i]
3066 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133067
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203068 result = _CheckWatchlistDefinitionsEntrySyntax(
3069 wd_key, wd_dict.values[i], ast)
3070 if result is not None:
3071 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133072
Sergey Ulanov4af16052018-11-08 02:41:463073 result = _CheckWatchlistsEntrySyntax(
3074 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203075 if result is not None:
3076 return 'Bad entry in WATCHLISTS dict: %s' % result
3077
3078 if wd_key.s != w_key.s:
3079 return mismatch_template % (
3080 '%s at line %d' % (wd_key.s, wd_key.lineno),
3081 '%s at line %d' % (w_key.s, w_key.lineno))
3082
3083 if wd_key.s < last_key:
3084 return (
3085 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3086 (wd_key.lineno, w_key.lineno))
3087 last_key = wd_key.s
3088
3089 i = i + 1
3090
3091
Sergey Ulanov4af16052018-11-08 02:41:463092def _CheckWATCHLISTSSyntax(expression, input_api):
3093 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203094 if not isinstance(expression, ast.Expression):
3095 return 'WATCHLISTS file must contain a valid expression'
3096 dictionary = expression.body
3097 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3098 return 'WATCHLISTS file must have single dict with exactly two entries'
3099
3100 first_key = dictionary.keys[0]
3101 first_value = dictionary.values[0]
3102 second_key = dictionary.keys[1]
3103 second_value = dictionary.values[1]
3104
3105 if (not isinstance(first_key, ast.Str) or
3106 first_key.s != 'WATCHLIST_DEFINITIONS' or
3107 not isinstance(first_value, ast.Dict)):
3108 return (
3109 'The first entry of the dict in WATCHLISTS file must be '
3110 'WATCHLIST_DEFINITIONS dict')
3111
3112 if (not isinstance(second_key, ast.Str) or
3113 second_key.s != 'WATCHLISTS' or
3114 not isinstance(second_value, ast.Dict)):
3115 return (
3116 'The second entry of the dict in WATCHLISTS file must be '
3117 'WATCHLISTS dict')
3118
Sergey Ulanov4af16052018-11-08 02:41:463119 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133120
3121
3122def _CheckWATCHLISTS(input_api, output_api):
3123 for f in input_api.AffectedFiles(include_deletes=False):
3124 if f.LocalPath() == 'WATCHLISTS':
3125 contents = input_api.ReadFile(f, 'r')
3126
3127 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203128 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133129 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203130 # Get an AST tree for it and scan the tree for detailed style checking.
3131 expression = input_api.ast.parse(
3132 contents, filename='WATCHLISTS', mode='eval')
3133 except ValueError as e:
3134 return [output_api.PresubmitError(
3135 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3136 except SyntaxError as e:
3137 return [output_api.PresubmitError(
3138 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3139 except TypeError as e:
3140 return [output_api.PresubmitError(
3141 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133142
Sergey Ulanov4af16052018-11-08 02:41:463143 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203144 if result is not None:
3145 return [output_api.PresubmitError(result)]
3146 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133147
3148 return []
3149
3150
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193151def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3152 """Checks that newly added header files have corresponding GN changes.
3153 Note that this is only a heuristic. To be precise, run script:
3154 build/check_gn_headers.py.
3155 """
3156
3157 def headers(f):
3158 return input_api.FilterSourceFile(
3159 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3160
3161 new_headers = []
3162 for f in input_api.AffectedSourceFiles(headers):
3163 if f.Action() != 'A':
3164 continue
3165 new_headers.append(f.LocalPath())
3166
3167 def gn_files(f):
3168 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3169
3170 all_gn_changed_contents = ''
3171 for f in input_api.AffectedSourceFiles(gn_files):
3172 for _, line in f.ChangedContents():
3173 all_gn_changed_contents += line
3174
3175 problems = []
3176 for header in new_headers:
3177 basename = input_api.os_path.basename(header)
3178 if basename not in all_gn_changed_contents:
3179 problems.append(header)
3180
3181 if problems:
3182 return [output_api.PresubmitPromptWarning(
3183 'Missing GN changes for new header files', items=sorted(problems),
3184 long_text='Please double check whether newly added header files need '
3185 'corresponding changes in gn or gni files.\nThis checking is only a '
3186 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3187 'Read https://crbug.com/661774 for more info.')]
3188 return []
3189
3190
Michael Giuffridad3bc8672018-10-25 22:48:023191def _CheckCorrectProductNameInMessages(input_api, output_api):
3192 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3193
3194 This assumes we won't intentionally reference one product from the other
3195 product.
3196 """
3197 all_problems = []
3198 test_cases = [{
3199 "filename_postfix": "google_chrome_strings.grd",
3200 "correct_name": "Chrome",
3201 "incorrect_name": "Chromium",
3202 }, {
3203 "filename_postfix": "chromium_strings.grd",
3204 "correct_name": "Chromium",
3205 "incorrect_name": "Chrome",
3206 }]
3207
3208 for test_case in test_cases:
3209 problems = []
3210 filename_filter = lambda x: x.LocalPath().endswith(
3211 test_case["filename_postfix"])
3212
3213 # Check each new line. Can yield false positives in multiline comments, but
3214 # easier than trying to parse the XML because messages can have nested
3215 # children, and associating message elements with affected lines is hard.
3216 for f in input_api.AffectedSourceFiles(filename_filter):
3217 for line_num, line in f.ChangedContents():
3218 if "<message" in line or "<!--" in line or "-->" in line:
3219 continue
3220 if test_case["incorrect_name"] in line:
3221 problems.append(
3222 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3223
3224 if problems:
3225 message = (
3226 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3227 % (test_case["correct_name"], test_case["correct_name"],
3228 test_case["incorrect_name"]))
3229 all_problems.append(
3230 output_api.PresubmitPromptWarning(message, items=problems))
3231
3232 return all_problems
3233
3234
Dirk Pranke3c18a382019-03-15 01:07:513235def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3236 # TODO(crbug.com/941824): We need to make sure the entries in
3237 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3238 # so that users of //buildtools in other projects get the same tooling
3239 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3240 # support to gclient, we can eliminate the duplication and delete
3241 # this presubmit check.
3242
3243 # Update this regexp if new revisions are added to the files.
3244 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013245 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513246
3247 # If a user is changing one revision, they need to change the same
3248 # line in both files. This means that any given change should contain
3249 # exactly the same list of changed lines that match the regexps. The
3250 # replace(' ', '') call allows us to ignore whitespace changes to the
3251 # lines. The 'long_text' parameter to the error will contain the
3252 # list of changed lines in both files, which should make it easy enough
3253 # to spot the error without going overboard in this implementation.
3254 revs_changes = {
3255 'DEPS': {},
3256 'buildtools/DEPS': {},
3257 }
3258 long_text = ''
3259
3260 for f in input_api.AffectedFiles(
3261 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3262 for line_num, line in f.ChangedContents():
3263 if rev_regexp.search(line):
3264 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3265 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3266
3267 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3268 return [output_api.PresubmitError(
3269 'Change buildtools revisions in sync in both //DEPS and '
3270 '//buildtools/DEPS.', long_text=long_text + '\n')]
3271 else:
3272 return []
3273
3274
dgnaa68d5e2015-06-10 10:08:223275def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573276 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223277 results = []
dgnaa68d5e2015-06-10 10:08:223278 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173279 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223280 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293281 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063282 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3283 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423284 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183285 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573286 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3287 return results
3288
3289def _AndroidSpecificOnCommitChecks(input_api, output_api):
3290 """Groups commit checks that target android code."""
3291 results = []
3292 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223293 return results
3294
3295
[email protected]22c9bd72011-03-27 16:47:393296def _CommonChecks(input_api, output_api):
3297 """Checks common to both upload and commit."""
3298 results = []
3299 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383300 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543301 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083302
3303 author = input_api.change.author_email
3304 if author and author not in _KNOWN_ROBOTS:
3305 results.extend(
3306 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3307
[email protected]55459852011-08-10 15:17:193308 results.extend(
[email protected]760deea2013-12-10 19:33:493309 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233310 results.extend(
3311 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543312 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183313 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343314 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523315 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223316 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443317 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593318 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063319 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123320 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183321 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223322 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303323 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493324 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033325 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493326 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443327 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273328 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073329 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543330 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443331 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393332 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553333 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043334 results.extend(
3335 input_api.canned_checks.CheckChangeHasNoTabs(
3336 input_api,
3337 output_api,
3338 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403339 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163340 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083341 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243342 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3343 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473344 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043345 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053346 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143347 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233348 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433349 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403350 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153351 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173352 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503353 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363354 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063355 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133356 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433357 results.extend(input_api.RunTests(
3358 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143359 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023360 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513361 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243362
Vaclav Brozekcdc7defb2018-03-20 09:54:353363 for f in input_api.AffectedFiles():
3364 path, name = input_api.os_path.split(f.LocalPath())
3365 if name == 'PRESUBMIT.py':
3366 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003367 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3368 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073369 # The PRESUBMIT.py file (and the directory containing it) might
3370 # have been affected by being moved or removed, so only try to
3371 # run the tests if they still exist.
3372 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3373 input_api, output_api, full_path,
3374 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393375 return results
[email protected]1f7b4172010-01-28 01:17:343376
[email protected]b337cb5b2011-01-23 21:24:053377
[email protected]b8079ae4a2012-12-05 19:56:493378def _CheckPatchFiles(input_api, output_api):
3379 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3380 if f.LocalPath().endswith(('.orig', '.rej'))]
3381 if problems:
3382 return [output_api.PresubmitError(
3383 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033384 else:
3385 return []
[email protected]b8079ae4a2012-12-05 19:56:493386
3387
Kent Tamura5a8755d2017-06-29 23:37:073388def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213389 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3390 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3391 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073392 include_re = input_api.re.compile(
3393 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3394 extension_re = input_api.re.compile(r'\.[a-z]+$')
3395 errors = []
3396 for f in input_api.AffectedFiles():
3397 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3398 continue
3399 found_line_number = None
3400 found_macro = None
3401 for line_num, line in f.ChangedContents():
3402 match = macro_re.search(line)
3403 if match:
3404 found_line_number = line_num
3405 found_macro = match.group(2)
3406 break
3407 if not found_line_number:
3408 continue
3409
3410 found_include = False
3411 for line in f.NewContents():
3412 if include_re.search(line):
3413 found_include = True
3414 break
3415 if found_include:
3416 continue
3417
3418 if not f.LocalPath().endswith('.h'):
3419 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3420 try:
3421 content = input_api.ReadFile(primary_header_path, 'r')
3422 if include_re.search(content):
3423 continue
3424 except IOError:
3425 pass
3426 errors.append('%s:%d %s macro is used without including build/'
3427 'build_config.h.'
3428 % (f.LocalPath(), found_line_number, found_macro))
3429 if errors:
3430 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3431 return []
3432
3433
[email protected]b00342e7f2013-03-26 16:21:543434def _DidYouMeanOSMacro(bad_macro):
3435 try:
3436 return {'A': 'OS_ANDROID',
3437 'B': 'OS_BSD',
3438 'C': 'OS_CHROMEOS',
3439 'F': 'OS_FREEBSD',
3440 'L': 'OS_LINUX',
3441 'M': 'OS_MACOSX',
3442 'N': 'OS_NACL',
3443 'O': 'OS_OPENBSD',
3444 'P': 'OS_POSIX',
3445 'S': 'OS_SOLARIS',
3446 'W': 'OS_WIN'}[bad_macro[3].upper()]
3447 except KeyError:
3448 return ''
3449
3450
3451def _CheckForInvalidOSMacrosInFile(input_api, f):
3452 """Check for sensible looking, totally invalid OS macros."""
3453 preprocessor_statement = input_api.re.compile(r'^\s*#')
3454 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3455 results = []
3456 for lnum, line in f.ChangedContents():
3457 if preprocessor_statement.search(line):
3458 for match in os_macro.finditer(line):
3459 if not match.group(1) in _VALID_OS_MACROS:
3460 good = _DidYouMeanOSMacro(match.group(1))
3461 did_you_mean = ' (did you mean %s?)' % good if good else ''
3462 results.append(' %s:%d %s%s' % (f.LocalPath(),
3463 lnum,
3464 match.group(1),
3465 did_you_mean))
3466 return results
3467
3468
3469def _CheckForInvalidOSMacros(input_api, output_api):
3470 """Check all affected files for invalid OS macros."""
3471 bad_macros = []
tzik3f295992018-12-04 20:32:233472 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473473 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543474 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3475
3476 if not bad_macros:
3477 return []
3478
3479 return [output_api.PresubmitError(
3480 'Possibly invalid OS macro[s] found. Please fix your code\n'
3481 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3482
lliabraa35bab3932014-10-01 12:16:443483
3484def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3485 """Check all affected files for invalid "if defined" macros."""
3486 ALWAYS_DEFINED_MACROS = (
3487 "TARGET_CPU_PPC",
3488 "TARGET_CPU_PPC64",
3489 "TARGET_CPU_68K",
3490 "TARGET_CPU_X86",
3491 "TARGET_CPU_ARM",
3492 "TARGET_CPU_MIPS",
3493 "TARGET_CPU_SPARC",
3494 "TARGET_CPU_ALPHA",
3495 "TARGET_IPHONE_SIMULATOR",
3496 "TARGET_OS_EMBEDDED",
3497 "TARGET_OS_IPHONE",
3498 "TARGET_OS_MAC",
3499 "TARGET_OS_UNIX",
3500 "TARGET_OS_WIN32",
3501 )
3502 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3503 results = []
3504 for lnum, line in f.ChangedContents():
3505 for match in ifdef_macro.finditer(line):
3506 if match.group(1) in ALWAYS_DEFINED_MACROS:
3507 always_defined = ' %s is always defined. ' % match.group(1)
3508 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3509 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3510 lnum,
3511 always_defined,
3512 did_you_mean))
3513 return results
3514
3515
3516def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3517 """Check all affected files for invalid "if defined" macros."""
3518 bad_macros = []
3519 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213520 if f.LocalPath().startswith('third_party/sqlite/'):
3521 continue
lliabraa35bab3932014-10-01 12:16:443522 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3523 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3524
3525 if not bad_macros:
3526 return []
3527
3528 return [output_api.PresubmitError(
3529 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3530 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3531 bad_macros)]
3532
3533
mlamouria82272622014-09-16 18:45:043534def _CheckForIPCRules(input_api, output_api):
3535 """Check for same IPC rules described in
3536 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3537 """
3538 base_pattern = r'IPC_ENUM_TRAITS\('
3539 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3540 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3541
3542 problems = []
3543 for f in input_api.AffectedSourceFiles(None):
3544 local_path = f.LocalPath()
3545 if not local_path.endswith('.h'):
3546 continue
3547 for line_number, line in f.ChangedContents():
3548 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3549 problems.append(
3550 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3551
3552 if problems:
3553 return [output_api.PresubmitPromptWarning(
3554 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3555 else:
3556 return []
3557
[email protected]b00342e7f2013-03-26 16:21:543558
Stephen Martinis97a394142018-06-07 23:06:053559def _CheckForLongPathnames(input_api, output_api):
3560 """Check to make sure no files being submitted have long paths.
3561 This causes issues on Windows.
3562 """
3563 problems = []
3564 for f in input_api.AffectedSourceFiles(None):
3565 local_path = f.LocalPath()
3566 # Windows has a path limit of 260 characters. Limit path length to 200 so
3567 # that we have some extra for the prefix on dev machines and the bots.
3568 if len(local_path) > 200:
3569 problems.append(local_path)
3570
3571 if problems:
3572 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3573 else:
3574 return []
3575
3576
Daniel Bratell8ba52722018-03-02 16:06:143577def _CheckForIncludeGuards(input_api, output_api):
3578 """Check that header files have proper guards against multiple inclusion.
3579 If a file should not have such guards (and it probably should) then it
3580 should include the string "no-include-guard-because-multiply-included".
3581 """
Daniel Bratell6a75baef62018-06-04 10:04:453582 def is_chromium_header_file(f):
3583 # We only check header files under the control of the Chromium
3584 # project. That is, those outside third_party apart from
3585 # third_party/blink.
3586 file_with_path = input_api.os_path.normpath(f.LocalPath())
3587 return (file_with_path.endswith('.h') and
3588 (not file_with_path.startswith('third_party') or
3589 file_with_path.startswith(
3590 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143591
3592 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343593 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143594
3595 errors = []
3596
Daniel Bratell6a75baef62018-06-04 10:04:453597 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143598 guard_name = None
3599 guard_line_number = None
3600 seen_guard_end = False
3601
3602 file_with_path = input_api.os_path.normpath(f.LocalPath())
3603 base_file_name = input_api.os_path.splitext(
3604 input_api.os_path.basename(file_with_path))[0]
3605 upper_base_file_name = base_file_name.upper()
3606
3607 expected_guard = replace_special_with_underscore(
3608 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143609
3610 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573611 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3612 # are too many (1000+) files with slight deviations from the
3613 # coding style. The most important part is that the include guard
3614 # is there, and that it's unique, not the name so this check is
3615 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143616 #
3617 # As code becomes more uniform, this could be made stricter.
3618
3619 guard_name_pattern_list = [
3620 # Anything with the right suffix (maybe with an extra _).
3621 r'\w+_H__?',
3622
Daniel Bratell39b5b062018-05-16 18:09:573623 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143624 r'\w+_h',
3625
3626 # Anything including the uppercase name of the file.
3627 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3628 upper_base_file_name)) + r'\w*',
3629 ]
3630 guard_name_pattern = '|'.join(guard_name_pattern_list)
3631 guard_pattern = input_api.re.compile(
3632 r'#ifndef\s+(' + guard_name_pattern + ')')
3633
3634 for line_number, line in enumerate(f.NewContents()):
3635 if 'no-include-guard-because-multiply-included' in line:
3636 guard_name = 'DUMMY' # To not trigger check outside the loop.
3637 break
3638
3639 if guard_name is None:
3640 match = guard_pattern.match(line)
3641 if match:
3642 guard_name = match.group(1)
3643 guard_line_number = line_number
3644
Daniel Bratell39b5b062018-05-16 18:09:573645 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453646 # don't match the chromium style guide, but new files should
3647 # get it right.
3648 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573649 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143650 errors.append(output_api.PresubmitPromptWarning(
3651 'Header using the wrong include guard name %s' % guard_name,
3652 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573653 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143654 else:
3655 # The line after #ifndef should have a #define of the same name.
3656 if line_number == guard_line_number + 1:
3657 expected_line = '#define %s' % guard_name
3658 if line != expected_line:
3659 errors.append(output_api.PresubmitPromptWarning(
3660 'Missing "%s" for include guard' % expected_line,
3661 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3662 'Expected: %r\nGot: %r' % (expected_line, line)))
3663
3664 if not seen_guard_end and line == '#endif // %s' % guard_name:
3665 seen_guard_end = True
3666 elif seen_guard_end:
3667 if line.strip() != '':
3668 errors.append(output_api.PresubmitPromptWarning(
3669 'Include guard %s not covering the whole file' % (
3670 guard_name), [f.LocalPath()]))
3671 break # Nothing else to check and enough to warn once.
3672
3673 if guard_name is None:
3674 errors.append(output_api.PresubmitPromptWarning(
3675 'Missing include guard %s' % expected_guard,
3676 [f.LocalPath()],
3677 'Missing include guard in %s\n'
3678 'Recommended name: %s\n'
3679 'This check can be disabled by having the string\n'
3680 'no-include-guard-because-multiply-included in the header.' %
3681 (f.LocalPath(), expected_guard)))
3682
3683 return errors
3684
3685
mostynbb639aca52015-01-07 20:31:233686def _CheckForWindowsLineEndings(input_api, output_api):
3687 """Check source code and known ascii text files for Windows style line
3688 endings.
3689 """
earthdok1b5e0ee2015-03-10 15:19:103690 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233691
3692 file_inclusion_pattern = (
3693 known_text_files,
3694 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3695 )
3696
mostynbb639aca52015-01-07 20:31:233697 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533698 source_file_filter = lambda f: input_api.FilterSourceFile(
3699 f, white_list=file_inclusion_pattern, black_list=None)
3700 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503701 include_file = False
3702 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233703 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503704 include_file = True
3705 if include_file:
3706 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233707
3708 if problems:
3709 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3710 'these files to contain Windows style line endings?\n' +
3711 '\n'.join(problems))]
3712
3713 return []
3714
3715
Vaclav Brozekd5de76a2018-03-17 07:57:503716def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133717 """Checks that all source files use SYSLOG properly."""
3718 syslog_files = []
3719 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563720 for line_number, line in f.ChangedContents():
3721 if 'SYSLOG' in line:
3722 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3723
pastarmovj89f7ee12016-09-20 14:58:133724 if syslog_files:
3725 return [output_api.PresubmitPromptWarning(
3726 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3727 ' calls.\nFiles to check:\n', items=syslog_files)]
3728 return []
3729
3730
[email protected]1f7b4172010-01-28 01:17:343731def CheckChangeOnUpload(input_api, output_api):
3732 results = []
3733 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473734 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283735 results.extend(
jam93a6ee792017-02-08 23:59:223736 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193737 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223738 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133739 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163740 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533741 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193742 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543743 return results
[email protected]ca8d1982009-02-19 16:33:123744
3745
[email protected]1bfb8322014-04-23 01:02:413746def GetTryServerMasterForBot(bot):
3747 """Returns the Try Server master for the given bot.
3748
[email protected]0bb112362014-07-26 04:38:323749 It tries to guess the master from the bot name, but may still fail
3750 and return None. There is no longer a default master.
3751 """
3752 # Potentially ambiguous bot names are listed explicitly.
3753 master_map = {
tandriie5587792016-07-14 00:34:503754 'chromium_presubmit': 'master.tryserver.chromium.linux',
3755 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413756 }
[email protected]0bb112362014-07-26 04:38:323757 master = master_map.get(bot)
3758 if not master:
wnwen4fbaab82016-05-25 12:54:363759 if 'android' in bot:
tandriie5587792016-07-14 00:34:503760 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363761 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503762 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323763 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503764 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323765 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503766 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323767 return master
[email protected]1bfb8322014-04-23 01:02:413768
3769
[email protected]ca8d1982009-02-19 16:33:123770def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543771 results = []
[email protected]1f7b4172010-01-28 01:17:343772 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573773 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543774 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273775 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343776 input_api,
3777 output_api,
[email protected]2fdd1f362013-01-16 03:56:033778 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273779
jam93a6ee792017-02-08 23:59:223780 results.extend(
3781 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543782 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3783 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413784 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3785 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543786 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143787
3788
3789def _CheckTranslationScreenshots(input_api, output_api):
3790 PART_FILE_TAG = "part"
3791 import os
3792 import sys
3793 from io import StringIO
3794
3795 try:
3796 old_sys_path = sys.path
3797 sys.path = sys.path + [input_api.os_path.join(
3798 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3799 import grit.grd_reader
3800 import grit.node.message
3801 import grit.util
3802 finally:
3803 sys.path = old_sys_path
3804
3805 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3806 """Load the grd file and return a dict of message ids to messages.
3807
3808 Ignores any nested grdp files pointed by <part> tag.
3809 """
3810 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3811 stop_after=None, first_ids_file=None,
3812 debug=False, defines=None,
3813 tags_to_ignore=set([PART_FILE_TAG]))
3814 return {
3815 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3816 grit.node.message.MessageNode)
3817 }
3818
3819 def _GetGrdpMessagesFromString(grdp_string):
3820 """Parses the contents of a grdp file given in grdp_string.
3821
3822 grd_reader can't parse grdp files directly. Instead, this creates a
3823 temporary directory with a grd file pointing to the grdp file, and loads the
3824 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3825 """
3826 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3827 <grit latest_public_release="1" current_release="1">
3828 <release seq="1">
3829 <messages>
3830 <part file="sub.grdp" />
3831 </messages>
3832 </release>
3833 </grit>
3834 """
3835 with grit.util.TempDir({'main.grd': WRAPPER,
3836 'sub.grdp': grdp_string}) as temp_dir:
3837 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3838
3839 new_or_added_paths = set(f.LocalPath()
3840 for f in input_api.AffectedFiles()
3841 if (f.Action() == 'A' or f.Action() == 'M'))
3842 removed_paths = set(f.LocalPath()
3843 for f in input_api.AffectedFiles(include_deletes=True)
3844 if f.Action() == 'D')
3845
3846 affected_grds = [f for f in input_api.AffectedFiles()
3847 if (f.LocalPath().endswith('.grd') or
3848 f.LocalPath().endswith('.grdp'))]
3849 affected_png_paths = [f.AbsoluteLocalPath()
3850 for f in input_api.AffectedFiles()
3851 if (f.LocalPath().endswith('.png'))]
3852
3853 # Check for screenshots. Developers can upload screenshots using
3854 # tools/translation/upload_screenshots.py which finds and uploads
3855 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3856 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3857 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3858 #
3859 # The logic here is as follows:
3860 #
3861 # - If the CL has a .png file under the screenshots directory for a grd
3862 # file, warn the developer. Actual images should never be checked into the
3863 # Chrome repo.
3864 #
3865 # - If the CL contains modified or new messages in grd files and doesn't
3866 # contain the corresponding .sha1 files, warn the developer to add images
3867 # and upload them via tools/translation/upload_screenshots.py.
3868 #
3869 # - If the CL contains modified or new messages in grd files and the
3870 # corresponding .sha1 files, everything looks good.
3871 #
3872 # - If the CL contains removed messages in grd files but the corresponding
3873 # .sha1 files aren't removed, warn the developer to remove them.
3874 unnecessary_screenshots = []
3875 missing_sha1 = []
3876 unnecessary_sha1_files = []
3877
3878
3879 def _CheckScreenshotAdded(screenshots_dir, message_id):
3880 sha1_path = input_api.os_path.join(
3881 screenshots_dir, message_id + '.png.sha1')
3882 if sha1_path not in new_or_added_paths:
3883 missing_sha1.append(sha1_path)
3884
3885
3886 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3887 sha1_path = input_api.os_path.join(
3888 screenshots_dir, message_id + '.png.sha1')
3889 if sha1_path not in removed_paths:
3890 unnecessary_sha1_files.append(sha1_path)
3891
3892
3893 for f in affected_grds:
3894 file_path = f.LocalPath()
3895 old_id_to_msg_map = {}
3896 new_id_to_msg_map = {}
3897 if file_path.endswith('.grdp'):
3898 if f.OldContents():
3899 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393900 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143901 if f.NewContents():
3902 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393903 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143904 else:
3905 if f.OldContents():
3906 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393907 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143908 if f.NewContents():
3909 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393910 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143911
3912 # Compute added, removed and modified message IDs.
3913 old_ids = set(old_id_to_msg_map)
3914 new_ids = set(new_id_to_msg_map)
3915 added_ids = new_ids - old_ids
3916 removed_ids = old_ids - new_ids
3917 modified_ids = set([])
3918 for key in old_ids.intersection(new_ids):
3919 if (old_id_to_msg_map[key].FormatXml()
3920 != new_id_to_msg_map[key].FormatXml()):
3921 modified_ids.add(key)
3922
3923 grd_name, ext = input_api.os_path.splitext(
3924 input_api.os_path.basename(file_path))
3925 screenshots_dir = input_api.os_path.join(
3926 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3927
3928 # Check the screenshot directory for .png files. Warn if there is any.
3929 for png_path in affected_png_paths:
3930 if png_path.startswith(screenshots_dir):
3931 unnecessary_screenshots.append(png_path)
3932
3933 for added_id in added_ids:
3934 _CheckScreenshotAdded(screenshots_dir, added_id)
3935
3936 for modified_id in modified_ids:
3937 _CheckScreenshotAdded(screenshots_dir, modified_id)
3938
3939 for removed_id in removed_ids:
3940 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3941
3942 results = []
3943 if unnecessary_screenshots:
3944 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393945 'Do not include actual screenshots in the changelist. Run '
3946 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143947 sorted(unnecessary_screenshots)))
3948
3949 if missing_sha1:
3950 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393951 'You are adding or modifying UI strings.\n'
3952 'To ensure the best translations, take screenshots of the relevant UI '
3953 '(https://g.co/chrome/translation) and add these files to your '
3954 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143955
3956 if unnecessary_sha1_files:
3957 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393958 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143959 sorted(unnecessary_sha1_files)))
3960
3961 return results