blob: 86afc51cce1ad5b47ef2056359b12868447d624a [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 ),
Avi Drissman7382afa02019-04-29 23:27:13195 (
196 'freeWhenDone:NO',
197 (
198 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
199 'Foundation types is prohibited.',
200 ),
201 True,
202 ),
[email protected]127f18ec2012-06-16 05:05:59203)
204
Daniel Bratell609102be2019-03-27 20:53:21205# Format: Sequence of tuples containing:
206# * String pattern or, if starting with a slash, a regular expression.
207# * Sequence of strings to show when the pattern matches.
208# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54209_BANNED_IOS_OBJC_FUNCTIONS = (
210 (
211 r'/\bTEST[(]',
212 (
213 'TEST() macro should not be used in Objective-C++ code as it does not ',
214 'drain the autorelease pool at the end of the test. Use TEST_F() ',
215 'macro instead with a fixture inheriting from PlatformTest (or a ',
216 'typedef).'
217 ),
218 True,
219 ),
220 (
221 r'/\btesting::Test\b',
222 (
223 'testing::Test should not be used in Objective-C++ code as it does ',
224 'not drain the autorelease pool at the end of the test. Use ',
225 'PlatformTest instead.'
226 ),
227 True,
228 ),
229)
230
[email protected]127f18ec2012-06-16 05:05:59231
Daniel Bratell609102be2019-03-27 20:53:21232# Format: Sequence of tuples containing:
233# * String pattern or, if starting with a slash, a regular expression.
234# * Sequence of strings to show when the pattern matches.
235# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
236# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59237_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20238 (
thomasandersone7caaa9b2017-03-29 19:22:53239 r'\bNULL\b',
240 (
241 'New code should not use NULL. Use nullptr instead.',
242 ),
243 True,
244 (),
245 ),
Antonio Gomes07300d02019-03-13 20:59:57246 # Make sure that gtest's FRIEND_TEST() macro is not used; the
247 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
248 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53249 (
[email protected]23e6cbc2012-06-16 18:51:20250 'FRIEND_TEST(',
251 (
[email protected]e3c945502012-06-26 20:01:49252 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20253 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
254 ),
255 False,
[email protected]7345da02012-11-27 14:31:49256 (),
[email protected]23e6cbc2012-06-16 18:51:20257 ),
258 (
thomasanderson4b569052016-09-14 20:15:53259 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
260 (
261 'Chrome clients wishing to select events on X windows should use',
262 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
263 'you are selecting events from the GPU process, or if you are using',
264 'an XDisplay other than gfx::GetXDisplay().',
265 ),
266 True,
267 (
Egor Paskoce145c42018-09-28 19:31:04268 r"^ui[\\/]gl[\\/].*\.cc$",
269 r"^media[\\/]gpu[\\/].*\.cc$",
270 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53271 ),
272 ),
273 (
thomasandersone043e3ce2017-06-08 00:43:20274 r'XInternAtom|xcb_intern_atom',
275 (
thomasanderson11aa41d2017-06-08 22:22:38276 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20277 ),
278 True,
279 (
Egor Paskoce145c42018-09-28 19:31:04280 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
281 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
282 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20283 ),
284 ),
285 (
tomhudsone2c14d552016-05-26 17:07:46286 'setMatrixClip',
287 (
288 'Overriding setMatrixClip() is prohibited; ',
289 'the base function is deprecated. ',
290 ),
291 True,
292 (),
293 ),
294 (
[email protected]52657f62013-05-20 05:30:31295 'SkRefPtr',
296 (
297 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22298 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31299 ),
300 True,
301 (),
302 ),
303 (
304 'SkAutoRef',
305 (
306 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22307 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31308 ),
309 True,
310 (),
311 ),
312 (
313 'SkAutoTUnref',
314 (
315 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22316 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31317 ),
318 True,
319 (),
320 ),
321 (
322 'SkAutoUnref',
323 (
324 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
325 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22326 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31327 ),
328 True,
329 (),
330 ),
[email protected]d89eec82013-12-03 14:10:59331 (
332 r'/HANDLE_EINTR\(.*close',
333 (
334 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
335 'descriptor will be closed, and it is incorrect to retry the close.',
336 'Either call close directly and ignore its return value, or wrap close',
337 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
338 ),
339 True,
340 (),
341 ),
342 (
343 r'/IGNORE_EINTR\((?!.*close)',
344 (
345 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
346 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
347 ),
348 True,
349 (
350 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04351 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
352 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59353 ),
354 ),
[email protected]ec5b3f02014-04-04 18:43:43355 (
356 r'/v8::Extension\(',
357 (
358 'Do not introduce new v8::Extensions into the code base, use',
359 'gin::Wrappable instead. See http://crbug.com/334679',
360 ),
361 True,
[email protected]f55c90ee62014-04-12 00:50:03362 (
Egor Paskoce145c42018-09-28 19:31:04363 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03364 ),
[email protected]ec5b3f02014-04-04 18:43:43365 ),
skyostilf9469f72015-04-20 10:38:52366 (
jame2d1a952016-04-02 00:27:10367 '#pragma comment(lib,',
368 (
369 'Specify libraries to link with in build files and not in the source.',
370 ),
371 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41372 (
tzik3f295992018-12-04 20:32:23373 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04374 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41375 ),
jame2d1a952016-04-02 00:27:10376 ),
fdorayc4ac18d2017-05-01 21:39:59377 (
Gabriel Charette7cc6c432018-04-25 20:52:02378 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59379 (
380 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
381 ),
382 False,
383 (),
384 ),
385 (
Gabriel Charette7cc6c432018-04-25 20:52:02386 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59387 (
388 'Consider using THREAD_CHECKER macros instead of the class directly.',
389 ),
390 False,
391 (),
392 ),
dbeamb6f4fde2017-06-15 04:03:06393 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06394 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
395 (
396 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
397 'deprecated (http://crbug.com/634507). Please avoid converting away',
398 'from the Time types in Chromium code, especially if any math is',
399 'being done on time values. For interfacing with platform/library',
400 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
401 'type converter methods instead. For faking TimeXXX values (for unit',
402 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
403 'other use cases, please contact base/time/OWNERS.',
404 ),
405 False,
406 (),
407 ),
408 (
dbeamb6f4fde2017-06-15 04:03:06409 'CallJavascriptFunctionUnsafe',
410 (
411 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
412 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
413 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
414 ),
415 False,
416 (
Egor Paskoce145c42018-09-28 19:31:04417 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
418 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
419 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06420 ),
421 ),
dskiba1474c2bfd62017-07-20 02:19:24422 (
423 'leveldb::DB::Open',
424 (
425 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
426 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
427 "Chrome's tracing, making their memory usage visible.",
428 ),
429 True,
430 (
431 r'^third_party/leveldatabase/.*\.(cc|h)$',
432 ),
Gabriel Charette0592c3a2017-07-26 12:02:04433 ),
434 (
Chris Mumfordc38afb62017-10-09 17:55:08435 'leveldb::NewMemEnv',
436 (
437 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58438 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
439 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08440 ),
441 True,
442 (
443 r'^third_party/leveldatabase/.*\.(cc|h)$',
444 ),
445 ),
446 (
Gabriel Charetted9839bc2017-07-29 14:17:47447 'RunLoop::QuitCurrent',
448 (
Robert Liao64b7ab22017-08-04 23:03:43449 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
450 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47451 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41452 False,
Gabriel Charetted9839bc2017-07-29 14:17:47453 (),
Gabriel Charettea44975052017-08-21 23:14:04454 ),
455 (
456 'base::ScopedMockTimeMessageLoopTaskRunner',
457 (
Gabriel Charette87cc1af2018-04-25 20:52:51458 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
459 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
460 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
461 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
462 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04463 ),
Gabriel Charette87cc1af2018-04-25 20:52:51464 False,
Gabriel Charettea44975052017-08-21 23:14:04465 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57466 ),
467 (
468 r'std::regex',
469 (
470 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02471 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57472 ),
473 True,
474 (),
Francois Doray43670e32017-09-27 12:40:38475 ),
476 (
Daniel Bratell69334cc2019-03-26 11:07:45477 r'/\bstd::to_string\b',
478 (
479 'std::to_string is locale dependent and slower than alternatives.',
480 'For locale-independent strings, e.g. writing numbers to and from',
481 'disk profiles, use base::NumberToString().',
482 'For user-visible strings, use base::FormatNumber() and',
483 'the related functions in base/i18n/number_formatting.h.',
484 ),
485 False, # Only a warning for now since it is already used,
Daniel Bratell609102be2019-03-27 20:53:21486 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45487 ),
488 (
489 r'/\bstd::shared_ptr\b',
490 (
491 'std::shared_ptr should not be used. Use scoped_refptr instead.',
492 ),
493 True,
Daniel Bratell609102be2019-03-27 20:53:21494 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
495 ),
496 (
497 r'/\blong long\b',
498 (
499 'long long is banned. Use stdint.h if you need a 64 bit number.',
500 ),
501 False, # Only a warning since it is already used.
502 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
503 ),
504 (
505 r'/\bstd::bind\b',
506 (
507 'std::bind is banned because of lifetime risks.',
508 'Use base::BindOnce or base::BindRepeating instead.',
509 ),
510 True,
511 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
512 ),
513 (
514 r'/\b#include <chrono>\b',
515 (
516 '<chrono> overlaps with Time APIs in base. Keep using',
517 'base classes.',
518 ),
519 True,
520 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
521 ),
522 (
523 r'/\b#include <exception>\b',
524 (
525 'Exceptions are banned and disabled in Chromium.',
526 ),
527 True,
528 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
529 ),
530 (
531 r'/\bstd::function\b',
532 (
533 'std::function is banned. Instead use base::Callback which directly',
534 'supports Chromium\'s weak pointers, ref counting and more.',
535 ),
536 False, # Only a warning since there are dozens of uses already.
537 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
538 ),
539 (
540 r'/\b#include <random>\b',
541 (
542 'Do not use any random number engines from <random>. Instead',
543 'use base::RandomBitGenerator.',
544 ),
545 True,
546 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
547 ),
548 (
549 r'/\bstd::ratio\b',
550 (
551 'std::ratio is banned by the Google Style Guide.',
552 ),
553 True,
554 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45555 ),
556 (
Francois Doray43670e32017-09-27 12:40:38557 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
558 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
559 (
560 'Use the new API in base/threading/thread_restrictions.h.',
561 ),
Gabriel Charette04b138f2018-08-06 00:03:22562 False,
Francois Doray43670e32017-09-27 12:40:38563 (),
564 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38565 (
566 r'/\bbase::Bind\(',
567 (
Gabriel Charette147335ea2018-03-22 15:59:19568 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02569 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38570 ),
571 False,
572 (),
573 ),
574 (
575 r'/\bbase::Callback<',
576 (
Gabriel Charette147335ea2018-03-22 15:59:19577 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02578 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38579 ),
580 False,
581 (),
582 ),
583 (
584 r'/\bbase::Closure\b',
585 (
Gabriel Charette147335ea2018-03-22 15:59:19586 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02587 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38588 ),
589 False,
590 (),
591 ),
Victor Costan3653df62018-02-08 21:38:16592 (
Alex Ilin5929abe32019-04-03 17:09:34593 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45594 (
595 'base::SharedMemory is deprecated. Please use',
596 '{Writable,ReadOnly}SharedMemoryRegion instead.',
597 ),
598 False,
599 (),
600 ),
601 (
Michael Giuffrida7f93d6922019-04-19 14:39:58602 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19603 (
604 'RunMessageLoop is deprecated, use RunLoop instead.',
605 ),
606 False,
607 (),
608 ),
609 (
610 r'RunThisRunLoop',
611 (
612 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
613 ),
614 False,
615 (),
616 ),
617 (
618 r'RunAllPendingInMessageLoop()',
619 (
620 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
621 "if you're convinced you need this.",
622 ),
623 False,
624 (),
625 ),
626 (
627 r'RunAllPendingInMessageLoop(BrowserThread',
628 (
629 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
630 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
631 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
632 'async events instead of flushing threads.',
633 ),
634 False,
635 (),
636 ),
637 (
638 r'MessageLoopRunner',
639 (
640 'MessageLoopRunner is deprecated, use RunLoop instead.',
641 ),
642 False,
643 (),
644 ),
645 (
646 r'GetDeferredQuitTaskForRunLoop',
647 (
648 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
649 "gab@ if you found a use case where this is the only solution.",
650 ),
651 False,
652 (),
653 ),
654 (
Victor Costane48a2e82019-03-15 22:02:34655 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16656 (
Victor Costane48a2e82019-03-15 22:02:34657 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16658 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
659 ),
660 True,
661 (
662 r'^sql/initialization\.(cc|h)$',
663 r'^third_party/sqlite/.*\.(c|cc|h)$',
664 ),
665 ),
Matt Menke7f520a82018-03-28 21:38:37666 (
667 'net::URLFetcher',
668 (
669 'net::URLFetcher should no longer be used in content embedders. ',
670 'Instead, use network::SimpleURLLoader instead, which supports ',
671 'an out-of-process network stack. ',
672 'net::URLFetcher may still be used in binaries that do not embed',
673 'content.',
674 ),
Matt Menke59716d02018-04-05 12:45:53675 False,
Matt Menke7f520a82018-03-28 21:38:37676 (
Egor Paskoce145c42018-09-28 19:31:04677 r'^ios[\\/].*\.(cc|h)$',
678 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37679 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04680 r'^net[\\/].*\.(cc|h)$',
681 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37682 ),
683 ),
jdoerried7d10ab2018-04-27 10:46:13684 (
tzik5de2157f2018-05-08 03:42:47685 r'std::random_shuffle',
686 (
687 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
688 'base::RandomShuffle instead.'
689 ),
690 True,
691 (),
692 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24693 (
694 'ios/web/public/test/http_server',
695 (
696 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
697 ),
698 False,
699 (),
700 ),
Robert Liao764c9492019-01-24 18:46:28701 (
702 'GetAddressOf',
703 (
704 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
705 'implicated in a few leaks. Use operator& instead.'
706 ),
707 True,
708 (),
709 ),
Antonio Gomes07300d02019-03-13 20:59:57710 (
711 'DEFINE_TYPE_CASTS',
712 (
713 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
714 '//third_party/blink/renderer/platform/casting.h.'
715 ),
716 True,
717 (
718 r'^third_party/blink/renderer/.*\.(cc|h)$',
719 ),
720 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38721 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37722 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38723 (
724 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
725 ),
726 True,
727 (),
728 ),
Ben Lewisa9514602019-04-29 17:53:05729 (
730 'SHFileOperation',
731 (
732 'SHFileOperation was deprecated in Windows Vista, and there are less ',
733 'complex functions to achieve the same goals. Use IFileOperation for ',
734 'any esoteric actions instead.'
735 ),
736 True,
737 (),
738 ),
Cliff Smolinskyb11abed2019-04-29 19:43:18739 (
Cliff Smolinsky81951642019-04-30 21:39:51740 'StringFromGUID2',
741 (
742 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
743 'Use base::win::String16FromGUID instead.'
744 ),
745 True,
746 (
747 r'/base/win/win_util_unittest.cc'
748 ),
749 ),
750 (
751 'StringFromCLSID',
752 (
753 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
754 'Use base::win::String16FromGUID instead.'
755 ),
756 True,
757 (
758 r'/base/win/win_util_unittest.cc'
759 ),
760 ),
761 (
Avi Drissman7382afa02019-04-29 23:27:13762 'kCFAllocatorNull',
763 (
764 'The use of kCFAllocatorNull with the NoCopy creation of ',
765 'CoreFoundation types is prohibited.',
766 ),
767 True,
768 (),
769 ),
[email protected]127f18ec2012-06-16 05:05:59770)
771
wnwenbdc444e2016-05-25 13:44:15772
mlamouria82272622014-09-16 18:45:04773_IPC_ENUM_TRAITS_DEPRECATED = (
774 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50775 'See http://www.chromium.org/Home/chromium-security/education/'
776 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04777
Stephen Martinis97a394142018-06-07 23:06:05778_LONG_PATH_ERROR = (
779 'Some files included in this CL have file names that are too long (> 200'
780 ' characters). If committed, these files will cause issues on Windows. See'
781 ' https://crbug.com/612667 for more details.'
782)
783
Shenghua Zhangbfaa38b82017-11-16 21:58:02784_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04785 r".*[\\/]BuildHooksAndroidImpl\.java",
786 r".*[\\/]LicenseContentProvider\.java",
787 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28788 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02789]
[email protected]127f18ec2012-06-16 05:05:59790
Sean Kau46e29bc2017-08-28 16:31:16791# These paths contain test data and other known invalid JSON files.
792_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04793 r'test[\\/]data[\\/]',
794 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
795 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04796 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43797 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16798]
799
800
[email protected]b00342e7f2013-03-26 16:21:54801_VALID_OS_MACROS = (
802 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08803 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54804 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12805 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54806 'OS_BSD',
807 'OS_CAT', # For testing.
808 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04809 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54810 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37811 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54812 'OS_IOS',
813 'OS_LINUX',
814 'OS_MACOSX',
815 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21816 'OS_NACL_NONSFI',
817 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12818 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54819 'OS_OPENBSD',
820 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37821 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54822 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54823 'OS_WIN',
824)
825
826
agrievef32bcc72016-04-04 14:57:40827_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39828 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36829 'base/android/jni_generator/jni_generator.pydeps',
830 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:22831 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36832 'build/android/gyp/aar.pydeps',
833 'build/android/gyp/aidl.pydeps',
834 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38835 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36836 'build/android/gyp/bytecode_processor.pydeps',
837 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57838 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36839 'build/android/gyp/create_bundle_wrapper_script.pydeps',
840 'build/android/gyp/copy_ex.pydeps',
841 'build/android/gyp/create_app_bundle.pydeps',
842 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36843 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22844 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36845 'build/android/gyp/create_stack_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36846 'build/android/gyp/create_tool_wrapper.pydeps',
847 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59848 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36849 'build/android/gyp/dex.pydeps',
850 'build/android/gyp/dist_aar.pydeps',
851 'build/android/gyp/emma_instr.pydeps',
852 'build/android/gyp/filter_zip.pydeps',
853 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36854 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36855 'build/android/gyp/ijar.pydeps',
856 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26857 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36858 'build/android/gyp/javac.pydeps',
859 'build/android/gyp/jinja_template.pydeps',
860 'build/android/gyp/lint.pydeps',
861 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36862 'build/android/gyp/merge_manifest.pydeps',
863 'build/android/gyp/prepare_resources.pydeps',
864 'build/android/gyp/proguard.pydeps',
865 'build/android/gyp/write_build_config.pydeps',
866 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56867 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36868 'build/android/incremental_install/generate_android_manifest.pydeps',
869 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22870 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40871 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04872 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36873 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:41874 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:19875 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:02876 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:40877]
878
wnwenbdc444e2016-05-25 13:44:15879
agrievef32bcc72016-04-04 14:57:40880_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40881 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29882 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
John Budorickbc3571aa2019-04-25 02:20:06883 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22884 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40885]
886
wnwenbdc444e2016-05-25 13:44:15887
agrievef32bcc72016-04-04 14:57:40888_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
889
890
Eric Boren6fd2b932018-01-25 15:05:08891# Bypass the AUTHORS check for these accounts.
892_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29893 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
894 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08895 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32896 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59897 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45898 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59899 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22900 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04901 ) | set('%[email protected]' % s
902 for s in ('chromium-autoroll',)
903 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30904 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08905
906
Daniel Bratell65b033262019-04-23 08:17:06907def _IsCPlusPlusFile(input_api, file_path):
908 """Returns True if this file contains C++-like code (and not Python,
909 Go, Java, MarkDown, ...)"""
910
911 ext = input_api.os_path.splitext(file_path)[1]
912 # This list is compatible with CppChecker.IsCppFile but we should
913 # consider adding ".c" to it. If we do that we can use this function
914 # at more places in the code.
915 return ext in (
916 '.h',
917 '.cc',
918 '.cpp',
919 '.m',
920 '.mm',
921 )
922
923def _IsCPlusPlusHeaderFile(input_api, file_path):
924 return input_api.os_path.splitext(file_path)[1] == ".h"
925
926
927def _IsJavaFile(input_api, file_path):
928 return input_api.os_path.splitext(file_path)[1] == ".java"
929
930
931def _IsProtoFile(input_api, file_path):
932 return input_api.os_path.splitext(file_path)[1] == ".proto"
933
[email protected]55459852011-08-10 15:17:19934def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
935 """Attempts to prevent use of functions intended only for testing in
936 non-testing code. For now this is just a best-effort implementation
937 that ignores header files and may have some false positives. A
938 better implementation would probably need a proper C++ parser.
939 """
940 # We only scan .cc files and the like, as the declaration of
941 # for-testing functions in header files are hard to distinguish from
942 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49943 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19944
jochenc0d4808c2015-07-27 09:25:42945 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19946 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09947 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19948 exclusion_pattern = input_api.re.compile(
949 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
950 base_function_pattern, base_function_pattern))
951
952 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44953 black_list = (_EXCLUDED_PATHS +
954 _TEST_CODE_EXCLUDED_PATHS +
955 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19956 return input_api.FilterSourceFile(
957 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49958 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19959 black_list=black_list)
960
961 problems = []
962 for f in input_api.AffectedSourceFiles(FilterFile):
963 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24964 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03965 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46966 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03967 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19968 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03969 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19970
971 if problems:
[email protected]f7051d52013-04-02 18:31:42972 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03973 else:
974 return []
[email protected]55459852011-08-10 15:17:19975
976
Vaclav Brozek7dbc28c2018-03-27 08:35:23977def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
978 """This is a simplified version of
979 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
980 """
981 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
982 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
983 name_pattern = r'ForTest(s|ing)?'
984 # Describes an occurrence of "ForTest*" inside a // comment.
985 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
986 # Catch calls.
987 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
988 # Ignore definitions. (Comments are ignored separately.)
989 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
990
991 problems = []
992 sources = lambda x: input_api.FilterSourceFile(
993 x,
994 black_list=(('(?i).*test', r'.*\/junit\/')
995 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49996 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23997 )
998 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
999 local_path = f.LocalPath()
1000 is_inside_javadoc = False
1001 for line_number, line in f.ChangedContents():
1002 if is_inside_javadoc and javadoc_end_re.search(line):
1003 is_inside_javadoc = False
1004 if not is_inside_javadoc and javadoc_start_re.search(line):
1005 is_inside_javadoc = True
1006 if is_inside_javadoc:
1007 continue
1008 if (inclusion_re.search(line) and
1009 not comment_re.search(line) and
1010 not exclusion_re.search(line)):
1011 problems.append(
1012 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1013
1014 if problems:
1015 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1016 else:
1017 return []
1018
1019
[email protected]10689ca2011-09-02 02:31:541020def _CheckNoIOStreamInHeaders(input_api, output_api):
1021 """Checks to make sure no .h files include <iostream>."""
1022 files = []
1023 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1024 input_api.re.MULTILINE)
1025 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1026 if not f.LocalPath().endswith('.h'):
1027 continue
1028 contents = input_api.ReadFile(f)
1029 if pattern.search(contents):
1030 files.append(f)
1031
1032 if len(files):
yolandyandaabc6d2016-04-18 18:29:391033 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061034 'Do not #include <iostream> in header files, since it inserts static '
1035 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541036 '#include <ostream>. See http://crbug.com/94794',
1037 files) ]
1038 return []
1039
Danil Chapovalov3518f362018-08-11 16:13:431040def _CheckNoStrCatRedefines(input_api, output_api):
1041 """Checks no windows headers with StrCat redefined are included directly."""
1042 files = []
1043 pattern_deny = input_api.re.compile(
1044 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1045 input_api.re.MULTILINE)
1046 pattern_allow = input_api.re.compile(
1047 r'^#include\s"base/win/windows_defines.inc"',
1048 input_api.re.MULTILINE)
1049 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1050 contents = input_api.ReadFile(f)
1051 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1052 files.append(f.LocalPath())
1053
1054 if len(files):
1055 return [output_api.PresubmitError(
1056 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1057 'directly since they pollute code with StrCat macro. Instead, '
1058 'include matching header from base/win. See http://crbug.com/856536',
1059 files) ]
1060 return []
1061
[email protected]10689ca2011-09-02 02:31:541062
[email protected]72df4e782012-06-21 16:28:181063def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521064 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181065 problems = []
1066 for f in input_api.AffectedFiles():
1067 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1068 continue
1069
1070 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041071 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181072 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1073
1074 if not problems:
1075 return []
1076 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1077 '\n'.join(problems))]
1078
Dominic Battre033531052018-09-24 15:45:341079def _CheckNoDISABLETypoInTests(input_api, output_api):
1080 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1081
1082 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1083 instead of DISABLED_. To filter false positives, reports are only generated
1084 if a corresponding MAYBE_ line exists.
1085 """
1086 problems = []
1087
1088 # The following two patterns are looked for in tandem - is a test labeled
1089 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1090 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1091 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1092
1093 # This is for the case that a test is disabled on all platforms.
1094 full_disable_pattern = input_api.re.compile(
1095 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1096 input_api.re.MULTILINE)
1097
Katie Df13948e2018-09-25 07:33:441098 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341099 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1100 continue
1101
1102 # Search for MABYE_, DISABLE_ pairs.
1103 disable_lines = {} # Maps of test name to line number.
1104 maybe_lines = {}
1105 for line_num, line in f.ChangedContents():
1106 disable_match = disable_pattern.search(line)
1107 if disable_match:
1108 disable_lines[disable_match.group(1)] = line_num
1109 maybe_match = maybe_pattern.search(line)
1110 if maybe_match:
1111 maybe_lines[maybe_match.group(1)] = line_num
1112
1113 # Search for DISABLE_ occurrences within a TEST() macro.
1114 disable_tests = set(disable_lines.keys())
1115 maybe_tests = set(maybe_lines.keys())
1116 for test in disable_tests.intersection(maybe_tests):
1117 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1118
1119 contents = input_api.ReadFile(f)
1120 full_disable_match = full_disable_pattern.search(contents)
1121 if full_disable_match:
1122 problems.append(' %s' % f.LocalPath())
1123
1124 if not problems:
1125 return []
1126 return [
1127 output_api.PresubmitPromptWarning(
1128 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1129 '\n'.join(problems))
1130 ]
1131
[email protected]72df4e782012-06-21 16:28:181132
danakj61c1aa22015-10-26 19:55:521133def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571134 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521135 errors = []
1136 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1137 input_api.re.MULTILINE)
1138 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1139 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1140 continue
1141 for lnum, line in f.ChangedContents():
1142 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171143 errors.append(output_api.PresubmitError(
1144 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571145 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171146 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521147 return errors
1148
1149
mcasasb7440c282015-02-04 14:52:191150def _FindHistogramNameInLine(histogram_name, line):
1151 """Tries to find a histogram name or prefix in a line."""
1152 if not "affected-histogram" in line:
1153 return histogram_name in line
1154 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1155 # the histogram_name.
1156 if not '"' in line:
1157 return False
1158 histogram_prefix = line.split('\"')[1]
1159 return histogram_prefix in histogram_name
1160
1161
1162def _CheckUmaHistogramChanges(input_api, output_api):
1163 """Check that UMA histogram names in touched lines can still be found in other
1164 lines of the patch or in histograms.xml. Note that this check would not catch
1165 the reverse: changes in histograms.xml not matched in the code itself."""
1166 touched_histograms = []
1167 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471168 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1169 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1170 name_pattern = r'"(.*?)"'
1171 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1172 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1173 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1174 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1175 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171176 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191177 for f in input_api.AffectedFiles():
1178 # If histograms.xml itself is modified, keep the modified lines for later.
1179 if f.LocalPath().endswith(('histograms.xml')):
1180 histograms_xml_modifications = f.ChangedContents()
1181 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471182 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1183 single_line_re = single_line_c_re
1184 split_line_prefix_re = split_line_c_prefix_re
1185 elif f.LocalPath().endswith(('java')):
1186 single_line_re = single_line_java_re
1187 split_line_prefix_re = split_line_java_prefix_re
1188 else:
mcasasb7440c282015-02-04 14:52:191189 continue
1190 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171191 if last_line_matched_prefix:
1192 suffix_found = split_line_suffix_re.search(line)
1193 if suffix_found :
1194 touched_histograms.append([suffix_found.group(1), f, line_num])
1195 last_line_matched_prefix = False
1196 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061197 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191198 if found:
1199 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171200 continue
1201 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191202
1203 # Search for the touched histogram names in the local modifications to
1204 # histograms.xml, and, if not found, on the base histograms.xml file.
1205 unmatched_histograms = []
1206 for histogram_info in touched_histograms:
1207 histogram_name_found = False
1208 for line_num, line in histograms_xml_modifications:
1209 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1210 if histogram_name_found:
1211 break
1212 if not histogram_name_found:
1213 unmatched_histograms.append(histogram_info)
1214
eromanb90c82e7e32015-04-01 15:13:491215 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191216 problems = []
1217 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491218 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191219 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451220 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191221 histogram_name_found = False
1222 for line in histograms_xml:
1223 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1224 if histogram_name_found:
1225 break
1226 if not histogram_name_found:
1227 problems.append(' [%s:%d] %s' %
1228 (f.LocalPath(), line_num, histogram_name))
1229
1230 if not problems:
1231 return []
1232 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1233 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491234 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191235
wnwenbdc444e2016-05-25 13:44:151236
yolandyandaabc6d2016-04-18 18:29:391237def _CheckFlakyTestUsage(input_api, output_api):
1238 """Check that FlakyTest annotation is our own instead of the android one"""
1239 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1240 files = []
1241 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1242 if f.LocalPath().endswith('Test.java'):
1243 if pattern.search(input_api.ReadFile(f)):
1244 files.append(f)
1245 if len(files):
1246 return [output_api.PresubmitError(
1247 'Use org.chromium.base.test.util.FlakyTest instead of '
1248 'android.test.FlakyTest',
1249 files)]
1250 return []
mcasasb7440c282015-02-04 14:52:191251
wnwenbdc444e2016-05-25 13:44:151252
[email protected]8ea5d4b2011-09-13 21:49:221253def _CheckNoNewWStrings(input_api, output_api):
1254 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271255 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221256 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201257 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571258 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341259 '/win/' in f.LocalPath() or
1260 'chrome_elf' in f.LocalPath() or
1261 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201262 continue
[email protected]8ea5d4b2011-09-13 21:49:221263
[email protected]a11dbe9b2012-08-07 01:32:581264 allowWString = False
[email protected]b5c24292011-11-28 14:38:201265 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581266 if 'presubmit: allow wstring' in line:
1267 allowWString = True
1268 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271269 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581270 allowWString = False
1271 else:
1272 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221273
[email protected]55463aa62011-10-12 00:48:271274 if not problems:
1275 return []
1276 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581277 ' If you are calling a cross-platform API that accepts a wstring, '
1278 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271279 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221280
1281
[email protected]2a8ac9c2011-10-19 17:20:441282def _CheckNoDEPSGIT(input_api, output_api):
1283 """Make sure .DEPS.git is never modified manually."""
1284 if any(f.LocalPath().endswith('.DEPS.git') for f in
1285 input_api.AffectedFiles()):
1286 return [output_api.PresubmitError(
1287 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1288 'automated system based on what\'s in DEPS and your changes will be\n'
1289 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501290 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1291 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441292 'for more information')]
1293 return []
1294
1295
tandriief664692014-09-23 14:51:471296def _CheckValidHostsInDEPS(input_api, output_api):
1297 """Checks that DEPS file deps are from allowed_hosts."""
1298 # Run only if DEPS file has been modified to annoy fewer bystanders.
1299 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1300 return []
1301 # Outsource work to gclient verify
1302 try:
John Budorickf20c0042019-04-25 23:23:401303 gclient_path = input_api.os_path.join(
1304 input_api.PresubmitLocalPath(),
1305 'third_party', 'depot_tools', 'gclient.py')
1306 input_api.subprocess.check_output(
1307 [input_api.python_executable, gclient_path, 'verify'],
1308 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471309 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201310 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471311 return [output_api.PresubmitError(
1312 'DEPS file must have only git dependencies.',
1313 long_text=error.output)]
1314
1315
[email protected]127f18ec2012-06-16 05:05:591316def _CheckNoBannedFunctions(input_api, output_api):
1317 """Make sure that banned functions are not used."""
1318 warnings = []
1319 errors = []
1320
wnwenbdc444e2016-05-25 13:44:151321 def IsBlacklisted(affected_file, blacklist):
1322 local_path = affected_file.LocalPath()
1323 for item in blacklist:
1324 if input_api.re.match(item, local_path):
1325 return True
1326 return False
1327
Sylvain Defresnea8b73d252018-02-28 15:45:541328 def IsIosObcjFile(affected_file):
1329 local_path = affected_file.LocalPath()
1330 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1331 return False
1332 basename = input_api.os_path.basename(local_path)
1333 if 'ios' in basename.split('_'):
1334 return True
1335 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1336 if sep and 'ios' in local_path.split(sep):
1337 return True
1338 return False
1339
wnwenbdc444e2016-05-25 13:44:151340 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1341 matched = False
1342 if func_name[0:1] == '/':
1343 regex = func_name[1:]
1344 if input_api.re.search(regex, line):
1345 matched = True
1346 elif func_name in line:
dchenge07de812016-06-20 19:27:171347 matched = True
wnwenbdc444e2016-05-25 13:44:151348 if matched:
dchenge07de812016-06-20 19:27:171349 problems = warnings
wnwenbdc444e2016-05-25 13:44:151350 if error:
dchenge07de812016-06-20 19:27:171351 problems = errors
wnwenbdc444e2016-05-25 13:44:151352 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1353 for message_line in message:
1354 problems.append(' %s' % message_line)
1355
Eric Stevensona9a980972017-09-23 00:04:411356 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1357 for f in input_api.AffectedFiles(file_filter=file_filter):
1358 for line_num, line in f.ChangedContents():
1359 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1360 CheckForMatch(f, line_num, line, func_name, message, error)
1361
[email protected]127f18ec2012-06-16 05:05:591362 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1363 for f in input_api.AffectedFiles(file_filter=file_filter):
1364 for line_num, line in f.ChangedContents():
1365 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151366 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591367
Sylvain Defresnea8b73d252018-02-28 15:45:541368 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1369 for line_num, line in f.ChangedContents():
1370 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1371 CheckForMatch(f, line_num, line, func_name, message, error)
1372
[email protected]127f18ec2012-06-16 05:05:591373 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1374 for f in input_api.AffectedFiles(file_filter=file_filter):
1375 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491376 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491377 if IsBlacklisted(f, excluded_paths):
1378 continue
wnwenbdc444e2016-05-25 13:44:151379 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591380
1381 result = []
1382 if (warnings):
1383 result.append(output_api.PresubmitPromptWarning(
1384 'Banned functions were used.\n' + '\n'.join(warnings)))
1385 if (errors):
1386 result.append(output_api.PresubmitError(
1387 'Banned functions were used.\n' + '\n'.join(errors)))
1388 return result
1389
1390
[email protected]6c063c62012-07-11 19:11:061391def _CheckNoPragmaOnce(input_api, output_api):
1392 """Make sure that banned functions are not used."""
1393 files = []
1394 pattern = input_api.re.compile(r'^#pragma\s+once',
1395 input_api.re.MULTILINE)
1396 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1397 if not f.LocalPath().endswith('.h'):
1398 continue
1399 contents = input_api.ReadFile(f)
1400 if pattern.search(contents):
1401 files.append(f)
1402
1403 if files:
1404 return [output_api.PresubmitError(
1405 'Do not use #pragma once in header files.\n'
1406 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1407 files)]
1408 return []
1409
[email protected]127f18ec2012-06-16 05:05:591410
[email protected]e7479052012-09-19 00:26:121411def _CheckNoTrinaryTrueFalse(input_api, output_api):
1412 """Checks to make sure we don't introduce use of foo ? true : false."""
1413 problems = []
1414 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1415 for f in input_api.AffectedFiles():
1416 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1417 continue
1418
1419 for line_num, line in f.ChangedContents():
1420 if pattern.match(line):
1421 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1422
1423 if not problems:
1424 return []
1425 return [output_api.PresubmitPromptWarning(
1426 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1427 '\n'.join(problems))]
1428
1429
[email protected]55f9f382012-07-31 11:02:181430def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281431 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181432 change. Breaking - rules is an error, breaking ! rules is a
1433 warning.
1434 """
mohan.reddyf21db962014-10-16 12:26:471435 import sys
[email protected]55f9f382012-07-31 11:02:181436 # We need to wait until we have an input_api object and use this
1437 # roundabout construct to import checkdeps because this file is
1438 # eval-ed and thus doesn't have __file__.
1439 original_sys_path = sys.path
1440 try:
1441 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471442 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181443 import checkdeps
[email protected]55f9f382012-07-31 11:02:181444 from rules import Rule
1445 finally:
1446 # Restore sys.path to what it was before.
1447 sys.path = original_sys_path
1448
1449 added_includes = []
rhalavati08acd232017-04-03 07:23:281450 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241451 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181452 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061453 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501454 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081455 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061456 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501457 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081458 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061459 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501460 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081461 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181462
[email protected]26385172013-05-09 23:11:351463 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181464
1465 error_descriptions = []
1466 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281467 error_subjects = set()
1468 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181469 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1470 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081471 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181472 description_with_path = '%s\n %s' % (path, rule_description)
1473 if rule_type == Rule.DISALLOW:
1474 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281475 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181476 else:
1477 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281478 warning_subjects.add("#includes")
1479
1480 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1481 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081482 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281483 description_with_path = '%s\n %s' % (path, rule_description)
1484 if rule_type == Rule.DISALLOW:
1485 error_descriptions.append(description_with_path)
1486 error_subjects.add("imports")
1487 else:
1488 warning_descriptions.append(description_with_path)
1489 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181490
Jinsuk Kim5a092672017-10-24 22:42:241491 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021492 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081493 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241494 description_with_path = '%s\n %s' % (path, rule_description)
1495 if rule_type == Rule.DISALLOW:
1496 error_descriptions.append(description_with_path)
1497 error_subjects.add("imports")
1498 else:
1499 warning_descriptions.append(description_with_path)
1500 warning_subjects.add("imports")
1501
[email protected]55f9f382012-07-31 11:02:181502 results = []
1503 if error_descriptions:
1504 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281505 'You added one or more %s that violate checkdeps rules.'
1506 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181507 error_descriptions))
1508 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421509 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281510 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181511 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281512 '%s? See relevant DEPS file(s) for details and contacts.' %
1513 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181514 warning_descriptions))
1515 return results
1516
1517
[email protected]fbcafe5a2012-08-08 15:31:221518def _CheckFilePermissions(input_api, output_api):
1519 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151520 if input_api.platform == 'win32':
1521 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291522 checkperms_tool = input_api.os_path.join(
1523 input_api.PresubmitLocalPath(),
1524 'tools', 'checkperms', 'checkperms.py')
1525 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471526 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391527 with input_api.CreateTemporaryFile() as file_list:
1528 for f in input_api.AffectedFiles():
1529 # checkperms.py file/directory arguments must be relative to the
1530 # repository.
1531 file_list.write(f.LocalPath() + '\n')
1532 file_list.close()
1533 args += ['--file-list', file_list.name]
1534 try:
1535 input_api.subprocess.check_output(args)
1536 return []
1537 except input_api.subprocess.CalledProcessError as error:
1538 return [output_api.PresubmitError(
1539 'checkperms.py failed:',
1540 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221541
1542
robertocn832f5992017-01-04 19:01:301543def _CheckTeamTags(input_api, output_api):
1544 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1545 checkteamtags_tool = input_api.os_path.join(
1546 input_api.PresubmitLocalPath(),
1547 'tools', 'checkteamtags', 'checkteamtags.py')
1548 args = [input_api.python_executable, checkteamtags_tool,
1549 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221550 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301551 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1552 'OWNERS']
1553 try:
1554 if files:
1555 input_api.subprocess.check_output(args + files)
1556 return []
1557 except input_api.subprocess.CalledProcessError as error:
1558 return [output_api.PresubmitError(
1559 'checkteamtags.py failed:',
1560 long_text=error.output)]
1561
1562
[email protected]c8278b32012-10-30 20:35:491563def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1564 """Makes sure we don't include ui/aura/window_property.h
1565 in header files.
1566 """
1567 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1568 errors = []
1569 for f in input_api.AffectedFiles():
1570 if not f.LocalPath().endswith('.h'):
1571 continue
1572 for line_num, line in f.ChangedContents():
1573 if pattern.match(line):
1574 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1575
1576 results = []
1577 if errors:
1578 results.append(output_api.PresubmitError(
1579 'Header files should not include ui/aura/window_property.h', errors))
1580 return results
1581
1582
[email protected]70ca77752012-11-20 03:45:031583def _CheckForVersionControlConflictsInFile(input_api, f):
1584 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1585 errors = []
1586 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161587 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231588 # First-level headers in markdown look a lot like version control
1589 # conflict markers. http://daringfireball.net/projects/markdown/basics
1590 continue
[email protected]70ca77752012-11-20 03:45:031591 if pattern.match(line):
1592 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1593 return errors
1594
1595
1596def _CheckForVersionControlConflicts(input_api, output_api):
1597 """Usually this is not intentional and will cause a compile failure."""
1598 errors = []
1599 for f in input_api.AffectedFiles():
1600 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1601
1602 results = []
1603 if errors:
1604 results.append(output_api.PresubmitError(
1605 'Version control conflict markers found, please resolve.', errors))
1606 return results
1607
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201608
estadee17314a02017-01-12 16:22:161609def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1610 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1611 errors = []
1612 for f in input_api.AffectedFiles():
1613 for line_num, line in f.ChangedContents():
1614 if pattern.search(line):
1615 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1616
1617 results = []
1618 if errors:
1619 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501620 'Found Google support URL addressed by answer number. Please replace '
1621 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161622 return results
1623
[email protected]70ca77752012-11-20 03:45:031624
[email protected]06e6d0ff2012-12-11 01:36:441625def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1626 def FilterFile(affected_file):
1627 """Filter function for use with input_api.AffectedSourceFiles,
1628 below. This filters out everything except non-test files from
1629 top-level directories that generally speaking should not hard-code
1630 service URLs (e.g. src/android_webview/, src/content/ and others).
1631 """
1632 return input_api.FilterSourceFile(
1633 affected_file,
Egor Paskoce145c42018-09-28 19:31:041634 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441635 black_list=(_EXCLUDED_PATHS +
1636 _TEST_CODE_EXCLUDED_PATHS +
1637 input_api.DEFAULT_BLACK_LIST))
1638
reillyi38965732015-11-16 18:27:331639 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1640 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461641 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1642 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441643 problems = [] # items are (filename, line_number, line)
1644 for f in input_api.AffectedSourceFiles(FilterFile):
1645 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461646 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441647 problems.append((f.LocalPath(), line_num, line))
1648
1649 if problems:
[email protected]f7051d52013-04-02 18:31:421650 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441651 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581652 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441653 [' %s:%d: %s' % (
1654 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031655 else:
1656 return []
[email protected]06e6d0ff2012-12-11 01:36:441657
1658
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491659# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271660def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1661 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311662 The native_client_sdk directory is excluded because it has auto-generated PNG
1663 files for documentation.
[email protected]d2530012013-01-25 16:39:271664 """
[email protected]d2530012013-01-25 16:39:271665 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491666 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041667 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311668 file_filter = lambda f: input_api.FilterSourceFile(
1669 f, white_list=white_list, black_list=black_list)
1670 for f in input_api.AffectedFiles(include_deletes=False,
1671 file_filter=file_filter):
1672 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271673
1674 results = []
1675 if errors:
1676 results.append(output_api.PresubmitError(
1677 'The name of PNG files should not have abbreviations. \n'
1678 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1679 'Contact [email protected] if you have questions.', errors))
1680 return results
1681
1682
Daniel Cheng4dcdb6b2017-04-13 08:30:171683def _ExtractAddRulesFromParsedDeps(parsed_deps):
1684 """Extract the rules that add dependencies from a parsed DEPS file.
1685
1686 Args:
1687 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1688 add_rules = set()
1689 add_rules.update([
1690 rule[1:] for rule in parsed_deps.get('include_rules', [])
1691 if rule.startswith('+') or rule.startswith('!')
1692 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501693 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171694 {}).iteritems():
1695 add_rules.update([
1696 rule[1:] for rule in rules
1697 if rule.startswith('+') or rule.startswith('!')
1698 ])
1699 return add_rules
1700
1701
1702def _ParseDeps(contents):
1703 """Simple helper for parsing DEPS files."""
1704 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171705 class _VarImpl:
1706
1707 def __init__(self, local_scope):
1708 self._local_scope = local_scope
1709
1710 def Lookup(self, var_name):
1711 """Implements the Var syntax."""
1712 try:
1713 return self._local_scope['vars'][var_name]
1714 except KeyError:
1715 raise Exception('Var is not defined: %s' % var_name)
1716
1717 local_scope = {}
1718 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171719 'Var': _VarImpl(local_scope).Lookup,
1720 }
1721 exec contents in global_scope, local_scope
1722 return local_scope
1723
1724
1725def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081726 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411727 a set of DEPS entries that we should look up.
1728
1729 For a directory (rather than a specific filename) we fake a path to
1730 a specific filename by adding /DEPS. This is chosen as a file that
1731 will seldom or never be subject to per-file include_rules.
1732 """
[email protected]2b438d62013-11-14 17:54:141733 # We ignore deps entries on auto-generated directories.
1734 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081735
Daniel Cheng4dcdb6b2017-04-13 08:30:171736 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1737 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1738
1739 added_deps = new_deps.difference(old_deps)
1740
[email protected]2b438d62013-11-14 17:54:141741 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171742 for added_dep in added_deps:
1743 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1744 continue
1745 # Assume that a rule that ends in .h is a rule for a specific file.
1746 if added_dep.endswith('.h'):
1747 results.add(added_dep)
1748 else:
1749 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081750 return results
1751
1752
[email protected]e871964c2013-05-13 14:14:551753def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1754 """When a dependency prefixed with + is added to a DEPS file, we
1755 want to make sure that the change is reviewed by an OWNER of the
1756 target file or directory, to avoid layering violations from being
1757 introduced. This check verifies that this happens.
1758 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171759 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241760
1761 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491762 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241763 for f in input_api.AffectedFiles(include_deletes=False,
1764 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551765 filename = input_api.os_path.basename(f.LocalPath())
1766 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171767 virtual_depended_on_files.update(_CalculateAddedDeps(
1768 input_api.os_path,
1769 '\n'.join(f.OldContents()),
1770 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551771
[email protected]e871964c2013-05-13 14:14:551772 if not virtual_depended_on_files:
1773 return []
1774
1775 if input_api.is_committing:
1776 if input_api.tbr:
1777 return [output_api.PresubmitNotifyResult(
1778 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271779 if input_api.dry_run:
1780 return [output_api.PresubmitNotifyResult(
1781 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551782 if not input_api.change.issue:
1783 return [output_api.PresubmitError(
1784 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401785 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551786 output = output_api.PresubmitError
1787 else:
1788 output = output_api.PresubmitNotifyResult
1789
1790 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501791 owner_email, reviewers = (
1792 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1793 input_api,
1794 owners_db.email_regexp,
1795 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551796
1797 owner_email = owner_email or input_api.change.author_email
1798
[email protected]de4f7d22013-05-23 14:27:461799 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511800 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461801 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551802 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1803 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411804
1805 # We strip the /DEPS part that was added by
1806 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1807 # directory.
1808 def StripDeps(path):
1809 start_deps = path.rfind('/DEPS')
1810 if start_deps != -1:
1811 return path[:start_deps]
1812 else:
1813 return path
1814 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551815 for path in missing_files]
1816
1817 if unapproved_dependencies:
1818 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151819 output('You need LGTM from owners of depends-on paths in DEPS that were '
1820 'modified in this CL:\n %s' %
1821 '\n '.join(sorted(unapproved_dependencies)))]
1822 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1823 output_list.append(output(
1824 'Suggested missing target path OWNERS:\n %s' %
1825 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551826 return output_list
1827
1828 return []
1829
1830
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491831# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401832def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491833 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401834 black_list = (_EXCLUDED_PATHS +
1835 _TEST_CODE_EXCLUDED_PATHS +
1836 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041837 (r"^base[\\/]logging\.h$",
1838 r"^base[\\/]logging\.cc$",
1839 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1840 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1841 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121842 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:181843 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Egor Paskoce145c42018-09-28 19:31:041844 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1845 r"^chrome[\\/]chrome_cleaner[\\/].*",
1846 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031847 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041848 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1849 r"^chromecast[\\/]",
1850 r"^cloud_print[\\/]",
1851 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481852 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041853 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311854 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041855 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461856 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041857 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461858 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041859 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251860 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041861 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1862 r"^courgette[\\/]courgette_tool\.cc$",
1863 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271864 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331865 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041866 r"^ipc[\\/]ipc_logging\.cc$",
1867 r"^native_client_sdk[\\/]",
1868 r"^remoting[\\/]base[\\/]logging\.h$",
1869 r"^remoting[\\/]host[\\/].*",
1870 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331871 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1872 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041873 r"^tools[\\/]",
1874 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1875 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331876 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401877 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491878 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401879
thomasanderson625d3932017-03-29 07:16:581880 log_info = set([])
1881 printf = set([])
[email protected]85218562013-11-22 07:41:401882
1883 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581884 for _, line in f.ChangedContents():
1885 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1886 log_info.add(f.LocalPath())
1887 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1888 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371889
thomasanderson625d3932017-03-29 07:16:581890 if input_api.re.search(r"\bprintf\(", line):
1891 printf.add(f.LocalPath())
1892 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1893 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401894
1895 if log_info:
1896 return [output_api.PresubmitError(
1897 'These files spam the console log with LOG(INFO):',
1898 items=log_info)]
1899 if printf:
1900 return [output_api.PresubmitError(
1901 'These files spam the console log with printf/fprintf:',
1902 items=printf)]
1903 return []
1904
1905
[email protected]49aa76a2013-12-04 06:59:161906def _CheckForAnonymousVariables(input_api, output_api):
1907 """These types are all expected to hold locks while in scope and
1908 so should never be anonymous (which causes them to be immediately
1909 destroyed)."""
1910 they_who_must_be_named = [
1911 'base::AutoLock',
1912 'base::AutoReset',
1913 'base::AutoUnlock',
1914 'SkAutoAlphaRestore',
1915 'SkAutoBitmapShaderInstall',
1916 'SkAutoBlitterChoose',
1917 'SkAutoBounderCommit',
1918 'SkAutoCallProc',
1919 'SkAutoCanvasRestore',
1920 'SkAutoCommentBlock',
1921 'SkAutoDescriptor',
1922 'SkAutoDisableDirectionCheck',
1923 'SkAutoDisableOvalCheck',
1924 'SkAutoFree',
1925 'SkAutoGlyphCache',
1926 'SkAutoHDC',
1927 'SkAutoLockColors',
1928 'SkAutoLockPixels',
1929 'SkAutoMalloc',
1930 'SkAutoMaskFreeImage',
1931 'SkAutoMutexAcquire',
1932 'SkAutoPathBoundsUpdate',
1933 'SkAutoPDFRelease',
1934 'SkAutoRasterClipValidate',
1935 'SkAutoRef',
1936 'SkAutoTime',
1937 'SkAutoTrace',
1938 'SkAutoUnref',
1939 ]
1940 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1941 # bad: base::AutoLock(lock.get());
1942 # not bad: base::AutoLock lock(lock.get());
1943 bad_pattern = input_api.re.compile(anonymous)
1944 # good: new base::AutoLock(lock.get())
1945 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1946 errors = []
1947
1948 for f in input_api.AffectedFiles():
1949 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1950 continue
1951 for linenum, line in f.ChangedContents():
1952 if bad_pattern.search(line) and not good_pattern.search(line):
1953 errors.append('%s:%d' % (f.LocalPath(), linenum))
1954
1955 if errors:
1956 return [output_api.PresubmitError(
1957 'These lines create anonymous variables that need to be named:',
1958 items=errors)]
1959 return []
1960
1961
Peter Kasting4844e46e2018-02-23 07:27:101962def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531963 # Returns whether |template_str| is of the form <T, U...> for some types T
1964 # and U. Assumes that |template_str| is already in the form <...>.
1965 def HasMoreThanOneArg(template_str):
1966 # Level of <...> nesting.
1967 nesting = 0
1968 for c in template_str:
1969 if c == '<':
1970 nesting += 1
1971 elif c == '>':
1972 nesting -= 1
1973 elif c == ',' and nesting == 1:
1974 return True
1975 return False
1976
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491977 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101978 sources = lambda affected_file: input_api.FilterSourceFile(
1979 affected_file,
1980 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1981 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491982 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551983
1984 # Pattern to capture a single "<...>" block of template arguments. It can
1985 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1986 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1987 # latter would likely require counting that < and > match, which is not
1988 # expressible in regular languages. Should the need arise, one can introduce
1989 # limited counting (matching up to a total number of nesting depth), which
1990 # should cover all practical cases for already a low nesting limit.
1991 template_arg_pattern = (
1992 r'<[^>]*' # Opening block of <.
1993 r'>([^<]*>)?') # Closing block of >.
1994 # Prefix expressing that whatever follows is not already inside a <...>
1995 # block.
1996 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101997 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551998 not_inside_template_arg_pattern
1999 + r'\bstd::unique_ptr'
2000 + template_arg_pattern
2001 + r'\(\)')
2002
2003 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2004 template_arg_no_array_pattern = (
2005 r'<[^>]*[^]]' # Opening block of <.
2006 r'>([^(<]*[^]]>)?') # Closing block of >.
2007 # Prefix saying that what follows is the start of an expression.
2008 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2009 # Suffix saying that what follows are call parentheses with a non-empty list
2010 # of arguments.
2011 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532012 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552013 return_construct_pattern = input_api.re.compile(
2014 start_of_expr_pattern
2015 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532016 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552017 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532018 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552019 + nonempty_arg_list_pattern)
2020
Vaclav Brozek851d9602018-04-04 16:13:052021 problems_constructor = []
2022 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102023 for f in input_api.AffectedSourceFiles(sources):
2024 for line_number, line in f.ChangedContents():
2025 # Disallow:
2026 # return std::unique_ptr<T>(foo);
2027 # bar = std::unique_ptr<T>(foo);
2028 # But allow:
2029 # return std::unique_ptr<T[]>(foo);
2030 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532031 # And also allow cases when the second template argument is present. Those
2032 # cases cannot be handled by std::make_unique:
2033 # return std::unique_ptr<T, U>(foo);
2034 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052035 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532036 return_construct_result = return_construct_pattern.search(line)
2037 if return_construct_result and not HasMoreThanOneArg(
2038 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052039 problems_constructor.append(
2040 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102041 # Disallow:
2042 # std::unique_ptr<T>()
2043 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052044 problems_nullptr.append(
2045 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2046
2047 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162048 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052049 errors.append(output_api.PresubmitError(
2050 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162051 problems_nullptr))
2052 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052053 errors.append(output_api.PresubmitError(
2054 'The following files use explicit std::unique_ptr constructor.'
2055 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162056 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102057 return errors
2058
2059
[email protected]999261d2014-03-03 20:08:082060def _CheckUserActionUpdate(input_api, output_api):
2061 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522062 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082063 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522064 # If actions.xml is already included in the changelist, the PRESUBMIT
2065 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082066 return []
2067
[email protected]999261d2014-03-03 20:08:082068 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2069 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522070 current_actions = None
[email protected]999261d2014-03-03 20:08:082071 for f in input_api.AffectedFiles(file_filter=file_filter):
2072 for line_num, line in f.ChangedContents():
2073 match = input_api.re.search(action_re, line)
2074 if match:
[email protected]2f92dec2014-03-07 19:21:522075 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2076 # loaded only once.
2077 if not current_actions:
2078 with open('tools/metrics/actions/actions.xml') as actions_f:
2079 current_actions = actions_f.read()
2080 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082081 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522082 action = 'name="{0}"'.format(action_name)
2083 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082084 return [output_api.PresubmitPromptWarning(
2085 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522086 'tools/metrics/actions/actions.xml. Please run '
2087 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082088 % (f.LocalPath(), line_num, action_name))]
2089 return []
2090
2091
Daniel Cheng13ca61a882017-08-25 15:11:252092def _ImportJSONCommentEater(input_api):
2093 import sys
2094 sys.path = sys.path + [input_api.os_path.join(
2095 input_api.PresubmitLocalPath(),
2096 'tools', 'json_comment_eater')]
2097 import json_comment_eater
2098 return json_comment_eater
2099
2100
[email protected]99171a92014-06-03 08:44:472101def _GetJSONParseError(input_api, filename, eat_comments=True):
2102 try:
2103 contents = input_api.ReadFile(filename)
2104 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252105 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132106 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472107
2108 input_api.json.loads(contents)
2109 except ValueError as e:
2110 return e
2111 return None
2112
2113
2114def _GetIDLParseError(input_api, filename):
2115 try:
2116 contents = input_api.ReadFile(filename)
2117 idl_schema = input_api.os_path.join(
2118 input_api.PresubmitLocalPath(),
2119 'tools', 'json_schema_compiler', 'idl_schema.py')
2120 process = input_api.subprocess.Popen(
2121 [input_api.python_executable, idl_schema],
2122 stdin=input_api.subprocess.PIPE,
2123 stdout=input_api.subprocess.PIPE,
2124 stderr=input_api.subprocess.PIPE,
2125 universal_newlines=True)
2126 (_, error) = process.communicate(input=contents)
2127 return error or None
2128 except ValueError as e:
2129 return e
2130
2131
2132def _CheckParseErrors(input_api, output_api):
2133 """Check that IDL and JSON files do not contain syntax errors."""
2134 actions = {
2135 '.idl': _GetIDLParseError,
2136 '.json': _GetJSONParseError,
2137 }
[email protected]99171a92014-06-03 08:44:472138 # Most JSON files are preprocessed and support comments, but these do not.
2139 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042140 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472141 ]
2142 # Only run IDL checker on files in these directories.
2143 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042144 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2145 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472146 ]
2147
2148 def get_action(affected_file):
2149 filename = affected_file.LocalPath()
2150 return actions.get(input_api.os_path.splitext(filename)[1])
2151
[email protected]99171a92014-06-03 08:44:472152 def FilterFile(affected_file):
2153 action = get_action(affected_file)
2154 if not action:
2155 return False
2156 path = affected_file.LocalPath()
2157
Sean Kau46e29bc2017-08-28 16:31:162158 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472159 return False
2160
2161 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162162 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472163 return False
2164 return True
2165
2166 results = []
2167 for affected_file in input_api.AffectedFiles(
2168 file_filter=FilterFile, include_deletes=False):
2169 action = get_action(affected_file)
2170 kwargs = {}
2171 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162172 _MatchesFile(input_api, json_no_comments_patterns,
2173 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472174 kwargs['eat_comments'] = False
2175 parse_error = action(input_api,
2176 affected_file.AbsoluteLocalPath(),
2177 **kwargs)
2178 if parse_error:
2179 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2180 (affected_file.LocalPath(), parse_error)))
2181 return results
2182
2183
[email protected]760deea2013-12-10 19:33:492184def _CheckJavaStyle(input_api, output_api):
2185 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472186 import sys
[email protected]760deea2013-12-10 19:33:492187 original_sys_path = sys.path
2188 try:
2189 sys.path = sys.path + [input_api.os_path.join(
2190 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2191 import checkstyle
2192 finally:
2193 # Restore sys.path to what it was before.
2194 sys.path = original_sys_path
2195
2196 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092197 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512198 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492199
2200
Sean Kau46e29bc2017-08-28 16:31:162201def _MatchesFile(input_api, patterns, path):
2202 for pattern in patterns:
2203 if input_api.re.search(pattern, path):
2204 return True
2205 return False
2206
2207
Daniel Cheng7052cdf2017-11-21 19:23:292208def _GetOwnersFilesToCheckForIpcOwners(input_api):
2209 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172210
Daniel Cheng7052cdf2017-11-21 19:23:292211 Returns:
2212 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2213 contain to cover IPC-related files with noparent reviewer rules.
2214 """
2215 # Whether or not a file affects IPC is (mostly) determined by a simple list
2216 # of filename patterns.
dchenge07de812016-06-20 19:27:172217 file_patterns = [
palmerb19a0932017-01-24 04:00:312218 # Legacy IPC:
dchenge07de812016-06-20 19:27:172219 '*_messages.cc',
2220 '*_messages*.h',
2221 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312222 # Mojo IPC:
dchenge07de812016-06-20 19:27:172223 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472224 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172225 '*_struct_traits*.*',
2226 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312227 '*.typemap',
2228 # Android native IPC:
2229 '*.aidl',
2230 # Blink uses a different file naming convention:
2231 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472232 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172233 '*StructTraits*.*',
2234 '*TypeConverter*.*',
2235 ]
2236
scottmg7a6ed5ba2016-11-04 18:22:042237 # These third_party directories do not contain IPCs, but contain files
2238 # matching the above patterns, which trigger false positives.
2239 exclude_paths = [
2240 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232241 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062242 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292243 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042244 ]
2245
dchenge07de812016-06-20 19:27:172246 # Dictionary mapping an OWNERS file path to Patterns.
2247 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2248 # rules ) to a PatternEntry.
2249 # PatternEntry is a dictionary with two keys:
2250 # - 'files': the files that are matched by this pattern
2251 # - 'rules': the per-file rules needed for this pattern
2252 # For example, if we expect OWNERS file to contain rules for *.mojom and
2253 # *_struct_traits*.*, Patterns might look like this:
2254 # {
2255 # '*.mojom': {
2256 # 'files': ...,
2257 # 'rules': [
2258 # 'per-file *.mojom=set noparent',
2259 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2260 # ],
2261 # },
2262 # '*_struct_traits*.*': {
2263 # 'files': ...,
2264 # 'rules': [
2265 # 'per-file *_struct_traits*.*=set noparent',
2266 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2267 # ],
2268 # },
2269 # }
2270 to_check = {}
2271
Daniel Cheng13ca61a882017-08-25 15:11:252272 def AddPatternToCheck(input_file, pattern):
2273 owners_file = input_api.os_path.join(
2274 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2275 if owners_file not in to_check:
2276 to_check[owners_file] = {}
2277 if pattern not in to_check[owners_file]:
2278 to_check[owners_file][pattern] = {
2279 'files': [],
2280 'rules': [
2281 'per-file %s=set noparent' % pattern,
2282 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2283 ]
2284 }
Vaclav Brozekd5de76a2018-03-17 07:57:502285 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252286
dchenge07de812016-06-20 19:27:172287 # Iterate through the affected files to see what we actually need to check
2288 # for. We should only nag patch authors about per-file rules if a file in that
2289 # directory would match that pattern. If a directory only contains *.mojom
2290 # files and no *_messages*.h files, we should only nag about rules for
2291 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252292 for f in input_api.AffectedFiles(include_deletes=False):
2293 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362294 # affected files for .json, .cc, and .h files which look like they contain
2295 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162296 if (f.LocalPath().endswith('.json') and
2297 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2298 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252299 json_comment_eater = _ImportJSONCommentEater(input_api)
2300 mostly_json_lines = '\n'.join(f.NewContents())
2301 # Comments aren't allowed in strict JSON, so filter them out.
2302 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432303 try:
2304 json_content = input_api.json.loads(json_lines)
2305 except:
2306 # There's another PRESUBMIT check that already verifies that JSON files
2307 # are not invalid, so no need to emit another warning here.
2308 continue
Daniel Cheng13ca61a882017-08-25 15:11:252309 if 'interface_provider_specs' in json_content:
2310 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362311 else:
2312 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2313 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2314 if (manifest_pattern.search(f.LocalPath()) and not
2315 test_manifest_pattern.search(f.LocalPath())):
2316 # We expect all actual service manifest files to contain at least one
2317 # qualified reference to service_manager::Manifest.
2318 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2319 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172320 for pattern in file_patterns:
2321 if input_api.fnmatch.fnmatch(
2322 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042323 skip = False
2324 for exclude in exclude_paths:
2325 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2326 skip = True
2327 break
2328 if skip:
2329 continue
Daniel Cheng13ca61a882017-08-25 15:11:252330 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172331 break
2332
Daniel Cheng7052cdf2017-11-21 19:23:292333 return to_check
2334
2335
2336def _CheckIpcOwners(input_api, output_api):
2337 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2338 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2339
2340 if to_check:
2341 # If there are any OWNERS files to check, there are IPC-related changes in
2342 # this CL. Auto-CC the review list.
2343 output_api.AppendCC('[email protected]')
2344
2345 # Go through the OWNERS files to check, filtering out rules that are already
2346 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172347 for owners_file, patterns in to_check.iteritems():
2348 try:
2349 with file(owners_file) as f:
2350 lines = set(f.read().splitlines())
2351 for entry in patterns.itervalues():
2352 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2353 ]
2354 except IOError:
2355 # No OWNERS file, so all the rules are definitely missing.
2356 continue
2357
2358 # All the remaining lines weren't found in OWNERS files, so emit an error.
2359 errors = []
2360 for owners_file, patterns in to_check.iteritems():
2361 missing_lines = []
2362 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502363 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172364 missing_lines.extend(entry['rules'])
2365 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2366 if missing_lines:
2367 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052368 'Because of the presence of files:\n%s\n\n'
2369 '%s needs the following %d lines added:\n\n%s' %
2370 ('\n'.join(files), owners_file, len(missing_lines),
2371 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172372
2373 results = []
2374 if errors:
vabrf5ce3bf92016-07-11 14:52:412375 if input_api.is_committing:
2376 output = output_api.PresubmitError
2377 else:
2378 output = output_api.PresubmitPromptWarning
2379 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592380 'Found OWNERS files that need to be updated for IPC security ' +
2381 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172382 long_text='\n\n'.join(errors)))
2383
2384 return results
2385
2386
jbriance9e12f162016-11-25 07:57:502387def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312388 """Checks that added or removed lines in non third party affected
2389 header files do not lead to new useless class or struct forward
2390 declaration.
jbriance9e12f162016-11-25 07:57:502391 """
2392 results = []
2393 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2394 input_api.re.MULTILINE)
2395 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2396 input_api.re.MULTILINE)
2397 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312398 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192399 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492400 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312401 continue
2402
jbriance9e12f162016-11-25 07:57:502403 if not f.LocalPath().endswith('.h'):
2404 continue
2405
2406 contents = input_api.ReadFile(f)
2407 fwd_decls = input_api.re.findall(class_pattern, contents)
2408 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2409
2410 useless_fwd_decls = []
2411 for decl in fwd_decls:
2412 count = sum(1 for _ in input_api.re.finditer(
2413 r'\b%s\b' % input_api.re.escape(decl), contents))
2414 if count == 1:
2415 useless_fwd_decls.append(decl)
2416
2417 if not useless_fwd_decls:
2418 continue
2419
2420 for line in f.GenerateScmDiff().splitlines():
2421 if (line.startswith('-') and not line.startswith('--') or
2422 line.startswith('+') and not line.startswith('++')):
2423 for decl in useless_fwd_decls:
2424 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2425 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242426 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502427 (f.LocalPath(), decl)))
2428 useless_fwd_decls.remove(decl)
2429
2430 return results
2431
Jinsong Fan91ebbbd2019-04-16 14:57:172432def _CheckAndroidDebuggableBuild(input_api, output_api):
2433 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2434 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2435 this is a debuggable build of Android.
2436 """
2437 build_type_check_pattern = input_api.re.compile(
2438 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2439
2440 errors = []
2441
2442 sources = lambda affected_file: input_api.FilterSourceFile(
2443 affected_file,
2444 black_list=(_EXCLUDED_PATHS +
2445 _TEST_CODE_EXCLUDED_PATHS +
2446 input_api.DEFAULT_BLACK_LIST +
2447 (r"^android_webview[\\/]support_library[\\/]"
2448 "boundary_interfaces[\\/]",
2449 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2450 r'^third_party[\\/].*',
2451 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2452 r"webview[\\/]chromium[\\/]License.*",)),
2453 white_list=[r'.*\.java$'])
2454
2455 for f in input_api.AffectedSourceFiles(sources):
2456 for line_num, line in f.ChangedContents():
2457 if build_type_check_pattern.search(line):
2458 errors.append("%s:%d" % (f.LocalPath(), line_num))
2459
2460 results = []
2461
2462 if errors:
2463 results.append(output_api.PresubmitPromptWarning(
2464 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2465 ' Please use BuildInfo.isDebugAndroid() instead.',
2466 errors))
2467
2468 return results
jbriance9e12f162016-11-25 07:57:502469
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492470# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292471def _CheckAndroidToastUsage(input_api, output_api):
2472 """Checks that code uses org.chromium.ui.widget.Toast instead of
2473 android.widget.Toast (Chromium Toast doesn't force hardware
2474 acceleration on low-end devices, saving memory).
2475 """
2476 toast_import_pattern = input_api.re.compile(
2477 r'^import android\.widget\.Toast;$')
2478
2479 errors = []
2480
2481 sources = lambda affected_file: input_api.FilterSourceFile(
2482 affected_file,
2483 black_list=(_EXCLUDED_PATHS +
2484 _TEST_CODE_EXCLUDED_PATHS +
2485 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042486 (r'^chromecast[\\/].*',
2487 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492488 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292489
2490 for f in input_api.AffectedSourceFiles(sources):
2491 for line_num, line in f.ChangedContents():
2492 if toast_import_pattern.search(line):
2493 errors.append("%s:%d" % (f.LocalPath(), line_num))
2494
2495 results = []
2496
2497 if errors:
2498 results.append(output_api.PresubmitError(
2499 'android.widget.Toast usage is detected. Android toasts use hardware'
2500 ' acceleration, and can be\ncostly on low-end devices. Please use'
2501 ' org.chromium.ui.widget.Toast instead.\n'
2502 'Contact [email protected] if you have any questions.',
2503 errors))
2504
2505 return results
2506
2507
dgnaa68d5e2015-06-10 10:08:222508def _CheckAndroidCrLogUsage(input_api, output_api):
2509 """Checks that new logs using org.chromium.base.Log:
2510 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512511 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222512 """
pkotwicza1dd0b002016-05-16 14:41:042513
torne89540622017-03-24 19:41:302514 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042515 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302516 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042517 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302518 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042519 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2520 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092521 # The customtabs_benchmark is a small app that does not depend on Chromium
2522 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042523 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042524 ]
2525
dgnaa68d5e2015-06-10 10:08:222526 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122527 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2528 class_in_base_pattern = input_api.re.compile(
2529 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2530 has_some_log_import_pattern = input_api.re.compile(
2531 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222532 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122533 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222534 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512535 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222536 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222537
Vincent Scheib16d7b272015-09-15 18:09:072538 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222539 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492540 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042541 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122542
dgnaa68d5e2015-06-10 10:08:222543 tag_decl_errors = []
2544 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122545 tag_errors = []
dgn38736db2015-09-18 19:20:512546 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122547 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222548
2549 for f in input_api.AffectedSourceFiles(sources):
2550 file_content = input_api.ReadFile(f)
2551 has_modified_logs = False
2552
2553 # Per line checks
dgn87d9fb62015-06-12 09:15:122554 if (cr_log_import_pattern.search(file_content) or
2555 (class_in_base_pattern.search(file_content) and
2556 not has_some_log_import_pattern.search(file_content))):
2557 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222558 for line_num, line in f.ChangedContents():
2559
2560 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122561 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222562 if match:
2563 has_modified_logs = True
2564
2565 # Make sure it uses "TAG"
2566 if not match.group('tag') == 'TAG':
2567 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122568 else:
2569 # Report non cr Log function calls in changed lines
2570 for line_num, line in f.ChangedContents():
2571 if log_call_pattern.search(line):
2572 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222573
2574 # Per file checks
2575 if has_modified_logs:
2576 # Make sure the tag is using the "cr" prefix and is not too long
2577 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512578 tag_name = match.group('name') if match else None
2579 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222580 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512581 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222582 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512583 elif '.' in tag_name:
2584 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222585
2586 results = []
2587 if tag_decl_errors:
2588 results.append(output_api.PresubmitPromptWarning(
2589 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512590 '"private static final String TAG = "<package tag>".\n'
2591 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222592 tag_decl_errors))
2593
2594 if tag_length_errors:
2595 results.append(output_api.PresubmitError(
2596 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512597 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222598 tag_length_errors))
2599
2600 if tag_errors:
2601 results.append(output_api.PresubmitPromptWarning(
2602 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2603 tag_errors))
2604
dgn87d9fb62015-06-12 09:15:122605 if util_log_errors:
dgn4401aa52015-04-29 16:26:172606 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122607 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2608 util_log_errors))
2609
dgn38736db2015-09-18 19:20:512610 if tag_with_dot_errors:
2611 results.append(output_api.PresubmitPromptWarning(
2612 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2613 tag_with_dot_errors))
2614
dgn4401aa52015-04-29 16:26:172615 return results
2616
2617
Yoland Yanb92fa522017-08-28 17:37:062618def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2619 """Checks that junit.framework.* is no longer used."""
2620 deprecated_junit_framework_pattern = input_api.re.compile(
2621 r'^import junit\.framework\..*;',
2622 input_api.re.MULTILINE)
2623 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492624 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062625 errors = []
2626 for f in input_api.AffectedFiles(sources):
2627 for line_num, line in f.ChangedContents():
2628 if deprecated_junit_framework_pattern.search(line):
2629 errors.append("%s:%d" % (f.LocalPath(), line_num))
2630
2631 results = []
2632 if errors:
2633 results.append(output_api.PresubmitError(
2634 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2635 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2636 ' if you have any question.', errors))
2637 return results
2638
2639
2640def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2641 """Checks that if new Java test classes have inheritance.
2642 Either the new test class is JUnit3 test or it is a JUnit4 test class
2643 with a base class, either case is undesirable.
2644 """
2645 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2646
2647 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492648 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062649 errors = []
2650 for f in input_api.AffectedFiles(sources):
2651 if not f.OldContents():
2652 class_declaration_start_flag = False
2653 for line_num, line in f.ChangedContents():
2654 if class_declaration_pattern.search(line):
2655 class_declaration_start_flag = True
2656 if class_declaration_start_flag and ' extends ' in line:
2657 errors.append('%s:%d' % (f.LocalPath(), line_num))
2658 if '{' in line:
2659 class_declaration_start_flag = False
2660
2661 results = []
2662 if errors:
2663 results.append(output_api.PresubmitPromptWarning(
2664 'The newly created files include Test classes that inherits from base'
2665 ' class. Please do not use inheritance in JUnit4 tests or add new'
2666 ' JUnit3 tests. Contact [email protected] if you have any'
2667 ' questions.', errors))
2668 return results
2669
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202670
yolandyan45001472016-12-21 21:12:422671def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2672 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2673 deprecated_annotation_import_pattern = input_api.re.compile(
2674 r'^import android\.test\.suitebuilder\.annotation\..*;',
2675 input_api.re.MULTILINE)
2676 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492677 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422678 errors = []
2679 for f in input_api.AffectedFiles(sources):
2680 for line_num, line in f.ChangedContents():
2681 if deprecated_annotation_import_pattern.search(line):
2682 errors.append("%s:%d" % (f.LocalPath(), line_num))
2683
2684 results = []
2685 if errors:
2686 results.append(output_api.PresubmitError(
2687 'Annotations in android.test.suitebuilder.annotation have been'
2688 ' deprecated since API level 24. Please use android.support.test.filters'
2689 ' from //third_party/android_support_test_runner:runner_java instead.'
2690 ' Contact [email protected] if you have any questions.', errors))
2691 return results
2692
2693
agrieve7b6479d82015-10-07 14:24:222694def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2695 """Checks if MDPI assets are placed in a correct directory."""
2696 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2697 ('/res/drawable/' in f.LocalPath() or
2698 '/res/drawable-ldrtl/' in f.LocalPath()))
2699 errors = []
2700 for f in input_api.AffectedFiles(include_deletes=False,
2701 file_filter=file_filter):
2702 errors.append(' %s' % f.LocalPath())
2703
2704 results = []
2705 if errors:
2706 results.append(output_api.PresubmitError(
2707 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2708 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2709 '/res/drawable-ldrtl/.\n'
2710 'Contact [email protected] if you have questions.', errors))
2711 return results
2712
2713
Nate Fischer535972b2017-09-16 01:06:182714def _CheckAndroidWebkitImports(input_api, output_api):
2715 """Checks that code uses org.chromium.base.Callback instead of
2716 android.widget.ValueCallback except in the WebView glue layer.
2717 """
2718 valuecallback_import_pattern = input_api.re.compile(
2719 r'^import android\.webkit\.ValueCallback;$')
2720
2721 errors = []
2722
2723 sources = lambda affected_file: input_api.FilterSourceFile(
2724 affected_file,
2725 black_list=(_EXCLUDED_PATHS +
2726 _TEST_CODE_EXCLUDED_PATHS +
2727 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042728 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492729 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182730
2731 for f in input_api.AffectedSourceFiles(sources):
2732 for line_num, line in f.ChangedContents():
2733 if valuecallback_import_pattern.search(line):
2734 errors.append("%s:%d" % (f.LocalPath(), line_num))
2735
2736 results = []
2737
2738 if errors:
2739 results.append(output_api.PresubmitError(
2740 'android.webkit.ValueCallback usage is detected outside of the glue'
2741 ' layer. To stay compatible with the support library, android.webkit.*'
2742 ' classes should only be used inside the glue layer and'
2743 ' org.chromium.base.Callback should be used instead.',
2744 errors))
2745
2746 return results
2747
2748
Becky Zhou7c69b50992018-12-10 19:37:572749def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2750 """Checks Android XML styles """
2751 import sys
2752 original_sys_path = sys.path
2753 try:
2754 sys.path = sys.path + [input_api.os_path.join(
2755 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2756 import checkxmlstyle
2757 finally:
2758 # Restore sys.path to what it was before.
2759 sys.path = original_sys_path
2760
2761 if is_check_on_upload:
2762 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2763 else:
2764 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2765
2766
agrievef32bcc72016-04-04 14:57:402767class PydepsChecker(object):
2768 def __init__(self, input_api, pydeps_files):
2769 self._file_cache = {}
2770 self._input_api = input_api
2771 self._pydeps_files = pydeps_files
2772
2773 def _LoadFile(self, path):
2774 """Returns the list of paths within a .pydeps file relative to //."""
2775 if path not in self._file_cache:
2776 with open(path) as f:
2777 self._file_cache[path] = f.read()
2778 return self._file_cache[path]
2779
2780 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2781 """Returns an interable of paths within the .pydep, relativized to //."""
2782 os_path = self._input_api.os_path
2783 pydeps_dir = os_path.dirname(pydeps_path)
2784 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2785 if not l.startswith('*'))
2786 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2787
2788 def _CreateFilesToPydepsMap(self):
2789 """Returns a map of local_path -> list_of_pydeps."""
2790 ret = {}
2791 for pydep_local_path in self._pydeps_files:
2792 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2793 ret.setdefault(path, []).append(pydep_local_path)
2794 return ret
2795
2796 def ComputeAffectedPydeps(self):
2797 """Returns an iterable of .pydeps files that might need regenerating."""
2798 affected_pydeps = set()
2799 file_to_pydeps_map = None
2800 for f in self._input_api.AffectedFiles(include_deletes=True):
2801 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:462802 # Changes to DEPS can lead to .pydeps changes if any .py files are in
2803 # subrepositories. We can't figure out which files change, so re-check
2804 # all files.
2805 # Changes to print_python_deps.py affect all .pydeps.
2806 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:402807 return self._pydeps_files
2808 elif local_path.endswith('.pydeps'):
2809 if local_path in self._pydeps_files:
2810 affected_pydeps.add(local_path)
2811 elif local_path.endswith('.py'):
2812 if file_to_pydeps_map is None:
2813 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2814 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2815 return affected_pydeps
2816
2817 def DetermineIfStale(self, pydeps_path):
2818 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412819 import difflib
John Budorick47ca3fe2018-02-10 00:53:102820 import os
2821
agrievef32bcc72016-04-04 14:57:402822 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2823 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102824 env = dict(os.environ)
2825 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402826 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102827 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412828 old_contents = old_pydeps_data[2:]
2829 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402830 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412831 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402832
2833
2834def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2835 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402836 # This check is for Python dependency lists (.pydeps files), and involves
2837 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2838 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282839 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002840 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022841 # TODO(agrieve): Update when there's a better way to detect
2842 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402843 is_android = input_api.os_path.exists('third_party/android_tools')
2844 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2845 results = []
2846 # First, check for new / deleted .pydeps.
2847 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032848 # Check whether we are running the presubmit check for a file in src.
2849 # f.LocalPath is relative to repo (src, or internal repo).
2850 # os_path.exists is relative to src repo.
2851 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2852 # to src and we can conclude that the pydeps is in src.
2853 if input_api.os_path.exists(f.LocalPath()):
2854 if f.LocalPath().endswith('.pydeps'):
2855 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2856 results.append(output_api.PresubmitError(
2857 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2858 'remove %s' % f.LocalPath()))
2859 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2860 results.append(output_api.PresubmitError(
2861 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2862 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402863
2864 if results:
2865 return results
2866
2867 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2868
2869 for pydep_path in checker.ComputeAffectedPydeps():
2870 try:
phajdan.jr0d9878552016-11-04 10:49:412871 result = checker.DetermineIfStale(pydep_path)
2872 if result:
2873 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402874 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412875 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2876 'To regenerate, run:\n\n %s' %
2877 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402878 except input_api.subprocess.CalledProcessError as error:
2879 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2880 long_text=error.output)]
2881
2882 return results
2883
2884
glidere61efad2015-02-18 17:39:432885def _CheckSingletonInHeaders(input_api, output_api):
2886 """Checks to make sure no header files have |Singleton<|."""
2887 def FileFilter(affected_file):
2888 # It's ok for base/memory/singleton.h to have |Singleton<|.
2889 black_list = (_EXCLUDED_PATHS +
2890 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042891 (r"^base[\\/]memory[\\/]singleton\.h$",
2892 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472893 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432894 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2895
sergeyu34d21222015-09-16 00:11:442896 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432897 files = []
2898 for f in input_api.AffectedSourceFiles(FileFilter):
2899 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2900 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2901 contents = input_api.ReadFile(f)
2902 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242903 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432904 pattern.search(line)):
2905 files.append(f)
2906 break
2907
2908 if files:
yolandyandaabc6d2016-04-18 18:29:392909 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442910 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432911 'Please move them to an appropriate source file so that the ' +
2912 'template gets instantiated in a single compilation unit.',
2913 files) ]
2914 return []
2915
2916
[email protected]fd20b902014-05-09 02:14:532917_DEPRECATED_CSS = [
2918 # Values
2919 ( "-webkit-box", "flex" ),
2920 ( "-webkit-inline-box", "inline-flex" ),
2921 ( "-webkit-flex", "flex" ),
2922 ( "-webkit-inline-flex", "inline-flex" ),
2923 ( "-webkit-min-content", "min-content" ),
2924 ( "-webkit-max-content", "max-content" ),
2925
2926 # Properties
2927 ( "-webkit-background-clip", "background-clip" ),
2928 ( "-webkit-background-origin", "background-origin" ),
2929 ( "-webkit-background-size", "background-size" ),
2930 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442931 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532932
2933 # Functions
2934 ( "-webkit-gradient", "gradient" ),
2935 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2936 ( "-webkit-linear-gradient", "linear-gradient" ),
2937 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2938 ( "-webkit-radial-gradient", "radial-gradient" ),
2939 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2940]
2941
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202942
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492943# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242944def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532945 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252946 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342947 documentation and iOS CSS for dom distiller
2948 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252949 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532950 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492951 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252952 black_list = (_EXCLUDED_PATHS +
2953 _TEST_CODE_EXCLUDED_PATHS +
2954 input_api.DEFAULT_BLACK_LIST +
2955 (r"^chrome/common/extensions/docs",
2956 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342957 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442958 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252959 r"^native_client_sdk"))
2960 file_filter = lambda f: input_api.FilterSourceFile(
2961 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532962 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2963 for line_num, line in fpath.ChangedContents():
2964 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022965 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532966 results.append(output_api.PresubmitError(
2967 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2968 (fpath.LocalPath(), line_num, deprecated_value, value)))
2969 return results
2970
mohan.reddyf21db962014-10-16 12:26:472971
dbeam070cfe62014-10-22 06:44:022972_DEPRECATED_JS = [
2973 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2974 ( "__defineGetter__", "Object.defineProperty" ),
2975 ( "__defineSetter__", "Object.defineProperty" ),
2976]
2977
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202978
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492979# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242980def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022981 """Make sure that we don't use deprecated JS in Chrome code."""
2982 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492983 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022984 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2985 input_api.DEFAULT_BLACK_LIST)
2986 file_filter = lambda f: input_api.FilterSourceFile(
2987 f, white_list=file_inclusion_pattern, black_list=black_list)
2988 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2989 for lnum, line in fpath.ChangedContents():
2990 for (deprecated, replacement) in _DEPRECATED_JS:
2991 if deprecated in line:
2992 results.append(output_api.PresubmitError(
2993 "%s:%d: Use of deprecated JS %s, use %s instead" %
2994 (fpath.LocalPath(), lnum, deprecated, replacement)))
2995 return results
2996
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202997
rlanday6802cf632017-05-30 17:48:362998def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:362999 bad_files = {}
3000 for f in input_api.AffectedFiles(include_deletes=False):
3001 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493002 not f.LocalPath().startswith('third_party/blink') and
3003 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363004 continue
3005
Daniel Bratell65b033262019-04-23 08:17:063006 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363007 continue
3008
Vaclav Brozekd5de76a2018-03-17 07:57:503009 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363010 if "#include" in line and "../" in line]
3011 if not relative_includes:
3012 continue
3013 bad_files[f.LocalPath()] = relative_includes
3014
3015 if not bad_files:
3016 return []
3017
3018 error_descriptions = []
3019 for file_path, bad_lines in bad_files.iteritems():
3020 error_description = file_path
3021 for line in bad_lines:
3022 error_description += '\n ' + line
3023 error_descriptions.append(error_description)
3024
3025 results = []
3026 results.append(output_api.PresubmitError(
3027 'You added one or more relative #include paths (including "../").\n'
3028 'These shouldn\'t be used because they can be used to include headers\n'
3029 'from code that\'s not correctly specified as a dependency in the\n'
3030 'relevant BUILD.gn file(s).',
3031 error_descriptions))
3032
3033 return results
3034
Takeshi Yoshinoe387aa32017-08-02 13:16:133035
Daniel Bratell65b033262019-04-23 08:17:063036def _CheckForCcIncludes(input_api, output_api):
3037 """Check that nobody tries to include a cc file. It's a relatively
3038 common error which results in duplicate symbols in object
3039 files. This may not always break the build until someone later gets
3040 very confusing linking errors."""
3041 results = []
3042 for f in input_api.AffectedFiles(include_deletes=False):
3043 # We let third_party code do whatever it wants
3044 if (f.LocalPath().startswith('third_party') and
3045 not f.LocalPath().startswith('third_party/blink') and
3046 not f.LocalPath().startswith('third_party\\blink')):
3047 continue
3048
3049 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3050 continue
3051
3052 for _, line in f.ChangedContents():
3053 if line.startswith('#include "'):
3054 included_file = line.split('"')[1]
3055 if _IsCPlusPlusFile(input_api, included_file):
3056 # The most common naming for external files with C++ code,
3057 # apart from standard headers, is to call them foo.inc, but
3058 # Chromium sometimes uses foo-inc.cc so allow that as well.
3059 if not included_file.endswith(('.h', '-inc.cc')):
3060 results.append(output_api.PresubmitError(
3061 'Only header files or .inc files should be included in other\n'
3062 'C++ files. Compiling the contents of a cc file more than once\n'
3063 'will cause duplicate information in the build which may later\n'
3064 'result in strange link_errors.\n' +
3065 f.LocalPath() + ':\n ' +
3066 line))
3067
3068 return results
3069
3070
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203071def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3072 if not isinstance(key, ast.Str):
3073 return 'Key at line %d must be a string literal' % key.lineno
3074 if not isinstance(value, ast.Dict):
3075 return 'Value at line %d must be a dict' % value.lineno
3076 if len(value.keys) != 1:
3077 return 'Dict at line %d must have single entry' % value.lineno
3078 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3079 return (
3080 'Entry at line %d must have a string literal \'filepath\' as key' %
3081 value.lineno)
3082 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133083
Takeshi Yoshinoe387aa32017-08-02 13:16:133084
Sergey Ulanov4af16052018-11-08 02:41:463085def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203086 if not isinstance(key, ast.Str):
3087 return 'Key at line %d must be a string literal' % key.lineno
3088 if not isinstance(value, ast.List):
3089 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463090 for element in value.elts:
3091 if not isinstance(element, ast.Str):
3092 return 'Watchlist elements on line %d is not a string' % key.lineno
3093 if not email_regex.match(element.s):
3094 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3095 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203096 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133097
Takeshi Yoshinoe387aa32017-08-02 13:16:133098
Sergey Ulanov4af16052018-11-08 02:41:463099def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203100 mismatch_template = (
3101 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3102 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133103
Sergey Ulanov4af16052018-11-08 02:41:463104 email_regex = input_api.re.compile(
3105 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3106
3107 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203108 i = 0
3109 last_key = ''
3110 while True:
3111 if i >= len(wd_dict.keys):
3112 if i >= len(w_dict.keys):
3113 return None
3114 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3115 elif i >= len(w_dict.keys):
3116 return (
3117 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133118
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203119 wd_key = wd_dict.keys[i]
3120 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133121
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203122 result = _CheckWatchlistDefinitionsEntrySyntax(
3123 wd_key, wd_dict.values[i], ast)
3124 if result is not None:
3125 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133126
Sergey Ulanov4af16052018-11-08 02:41:463127 result = _CheckWatchlistsEntrySyntax(
3128 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203129 if result is not None:
3130 return 'Bad entry in WATCHLISTS dict: %s' % result
3131
3132 if wd_key.s != w_key.s:
3133 return mismatch_template % (
3134 '%s at line %d' % (wd_key.s, wd_key.lineno),
3135 '%s at line %d' % (w_key.s, w_key.lineno))
3136
3137 if wd_key.s < last_key:
3138 return (
3139 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3140 (wd_key.lineno, w_key.lineno))
3141 last_key = wd_key.s
3142
3143 i = i + 1
3144
3145
Sergey Ulanov4af16052018-11-08 02:41:463146def _CheckWATCHLISTSSyntax(expression, input_api):
3147 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203148 if not isinstance(expression, ast.Expression):
3149 return 'WATCHLISTS file must contain a valid expression'
3150 dictionary = expression.body
3151 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3152 return 'WATCHLISTS file must have single dict with exactly two entries'
3153
3154 first_key = dictionary.keys[0]
3155 first_value = dictionary.values[0]
3156 second_key = dictionary.keys[1]
3157 second_value = dictionary.values[1]
3158
3159 if (not isinstance(first_key, ast.Str) or
3160 first_key.s != 'WATCHLIST_DEFINITIONS' or
3161 not isinstance(first_value, ast.Dict)):
3162 return (
3163 'The first entry of the dict in WATCHLISTS file must be '
3164 'WATCHLIST_DEFINITIONS dict')
3165
3166 if (not isinstance(second_key, ast.Str) or
3167 second_key.s != 'WATCHLISTS' or
3168 not isinstance(second_value, ast.Dict)):
3169 return (
3170 'The second entry of the dict in WATCHLISTS file must be '
3171 'WATCHLISTS dict')
3172
Sergey Ulanov4af16052018-11-08 02:41:463173 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133174
3175
3176def _CheckWATCHLISTS(input_api, output_api):
3177 for f in input_api.AffectedFiles(include_deletes=False):
3178 if f.LocalPath() == 'WATCHLISTS':
3179 contents = input_api.ReadFile(f, 'r')
3180
3181 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203182 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133183 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203184 # Get an AST tree for it and scan the tree for detailed style checking.
3185 expression = input_api.ast.parse(
3186 contents, filename='WATCHLISTS', mode='eval')
3187 except ValueError as e:
3188 return [output_api.PresubmitError(
3189 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3190 except SyntaxError as e:
3191 return [output_api.PresubmitError(
3192 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3193 except TypeError as e:
3194 return [output_api.PresubmitError(
3195 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133196
Sergey Ulanov4af16052018-11-08 02:41:463197 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203198 if result is not None:
3199 return [output_api.PresubmitError(result)]
3200 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133201
3202 return []
3203
3204
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193205def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3206 """Checks that newly added header files have corresponding GN changes.
3207 Note that this is only a heuristic. To be precise, run script:
3208 build/check_gn_headers.py.
3209 """
3210
3211 def headers(f):
3212 return input_api.FilterSourceFile(
3213 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3214
3215 new_headers = []
3216 for f in input_api.AffectedSourceFiles(headers):
3217 if f.Action() != 'A':
3218 continue
3219 new_headers.append(f.LocalPath())
3220
3221 def gn_files(f):
3222 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3223
3224 all_gn_changed_contents = ''
3225 for f in input_api.AffectedSourceFiles(gn_files):
3226 for _, line in f.ChangedContents():
3227 all_gn_changed_contents += line
3228
3229 problems = []
3230 for header in new_headers:
3231 basename = input_api.os_path.basename(header)
3232 if basename not in all_gn_changed_contents:
3233 problems.append(header)
3234
3235 if problems:
3236 return [output_api.PresubmitPromptWarning(
3237 'Missing GN changes for new header files', items=sorted(problems),
3238 long_text='Please double check whether newly added header files need '
3239 'corresponding changes in gn or gni files.\nThis checking is only a '
3240 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3241 'Read https://crbug.com/661774 for more info.')]
3242 return []
3243
3244
Michael Giuffridad3bc8672018-10-25 22:48:023245def _CheckCorrectProductNameInMessages(input_api, output_api):
3246 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3247
3248 This assumes we won't intentionally reference one product from the other
3249 product.
3250 """
3251 all_problems = []
3252 test_cases = [{
3253 "filename_postfix": "google_chrome_strings.grd",
3254 "correct_name": "Chrome",
3255 "incorrect_name": "Chromium",
3256 }, {
3257 "filename_postfix": "chromium_strings.grd",
3258 "correct_name": "Chromium",
3259 "incorrect_name": "Chrome",
3260 }]
3261
3262 for test_case in test_cases:
3263 problems = []
3264 filename_filter = lambda x: x.LocalPath().endswith(
3265 test_case["filename_postfix"])
3266
3267 # Check each new line. Can yield false positives in multiline comments, but
3268 # easier than trying to parse the XML because messages can have nested
3269 # children, and associating message elements with affected lines is hard.
3270 for f in input_api.AffectedSourceFiles(filename_filter):
3271 for line_num, line in f.ChangedContents():
3272 if "<message" in line or "<!--" in line or "-->" in line:
3273 continue
3274 if test_case["incorrect_name"] in line:
3275 problems.append(
3276 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3277
3278 if problems:
3279 message = (
3280 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3281 % (test_case["correct_name"], test_case["correct_name"],
3282 test_case["incorrect_name"]))
3283 all_problems.append(
3284 output_api.PresubmitPromptWarning(message, items=problems))
3285
3286 return all_problems
3287
3288
Dirk Pranke3c18a382019-03-15 01:07:513289def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3290 # TODO(crbug.com/941824): We need to make sure the entries in
3291 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3292 # so that users of //buildtools in other projects get the same tooling
3293 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3294 # support to gclient, we can eliminate the duplication and delete
3295 # this presubmit check.
3296
3297 # Update this regexp if new revisions are added to the files.
3298 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013299 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513300
3301 # If a user is changing one revision, they need to change the same
3302 # line in both files. This means that any given change should contain
3303 # exactly the same list of changed lines that match the regexps. The
3304 # replace(' ', '') call allows us to ignore whitespace changes to the
3305 # lines. The 'long_text' parameter to the error will contain the
3306 # list of changed lines in both files, which should make it easy enough
3307 # to spot the error without going overboard in this implementation.
3308 revs_changes = {
3309 'DEPS': {},
3310 'buildtools/DEPS': {},
3311 }
3312 long_text = ''
3313
3314 for f in input_api.AffectedFiles(
3315 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3316 for line_num, line in f.ChangedContents():
3317 if rev_regexp.search(line):
3318 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3319 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3320
3321 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3322 return [output_api.PresubmitError(
3323 'Change buildtools revisions in sync in both //DEPS and '
3324 '//buildtools/DEPS.', long_text=long_text + '\n')]
3325 else:
3326 return []
3327
3328
Daniel Bratell93eb6c62019-04-29 20:13:363329def _CheckForTooLargeFiles(input_api, output_api):
3330 """Avoid large files, especially binary files, in the repository since
3331 git doesn't scale well for those. They will be in everyone's repo
3332 clones forever, forever making Chromium slower to clone and work
3333 with."""
3334
3335 # Uploading files to cloud storage is not trivial so we don't want
3336 # to set the limit too low, but the upper limit for "normal" large
3337 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
3338 # anything over 20 MB is exceptional.
3339 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
3340
3341 too_large_files = []
3342 for f in input_api.AffectedFiles():
3343 # Check both added and modified files (but not deleted files).
3344 if f.Action() in ('A', 'M'):
3345 size = input_api.os_path.getsize(f.LocalPath())
3346 if size > TOO_LARGE_FILE_SIZE_LIMIT:
3347 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
3348
3349 if too_large_files:
3350 message = (
3351 'Do not commit large files to git since git scales badly for those.\n' +
3352 'Instead put the large files in cloud storage and use DEPS to\n' +
3353 'fetch them.\n' + '\n'.join(too_large_files)
3354 )
3355 return [output_api.PresubmitError(
3356 'Too large files found in commit', long_text=message + '\n')]
3357 else:
3358 return []
3359
dgnaa68d5e2015-06-10 10:08:223360def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573361 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223362 results = []
dgnaa68d5e2015-06-10 10:08:223363 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173364 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223365 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293366 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063367 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3368 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423369 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183370 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573371 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3372 return results
3373
3374def _AndroidSpecificOnCommitChecks(input_api, output_api):
3375 """Groups commit checks that target android code."""
3376 results = []
3377 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223378 return results
3379
3380
[email protected]22c9bd72011-03-27 16:47:393381def _CommonChecks(input_api, output_api):
3382 """Checks common to both upload and commit."""
3383 results = []
3384 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383385 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543386 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083387
3388 author = input_api.change.author_email
3389 if author and author not in _KNOWN_ROBOTS:
3390 results.extend(
3391 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3392
[email protected]55459852011-08-10 15:17:193393 results.extend(
[email protected]760deea2013-12-10 19:33:493394 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233395 results.extend(
3396 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543397 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183398 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343399 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523400 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223401 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443402 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593403 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063404 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123405 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183406 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223407 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303408 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493409 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033410 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493411 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443412 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273413 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073414 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543415 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443416 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393417 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553418 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043419 results.extend(
3420 input_api.canned_checks.CheckChangeHasNoTabs(
3421 input_api,
3422 output_api,
3423 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403424 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163425 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083426 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243427 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3428 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473429 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043430 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053431 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143432 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233433 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433434 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403435 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153436 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173437 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503438 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363439 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063440 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133441 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433442 results.extend(input_api.RunTests(
3443 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143444 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023445 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513446 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
Daniel Bratell93eb6c62019-04-29 20:13:363447 results.extend(_CheckForTooLargeFiles(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243448
Vaclav Brozekcdc7defb2018-03-20 09:54:353449 for f in input_api.AffectedFiles():
3450 path, name = input_api.os_path.split(f.LocalPath())
3451 if name == 'PRESUBMIT.py':
3452 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003453 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3454 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073455 # The PRESUBMIT.py file (and the directory containing it) might
3456 # have been affected by being moved or removed, so only try to
3457 # run the tests if they still exist.
3458 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3459 input_api, output_api, full_path,
3460 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393461 return results
[email protected]1f7b4172010-01-28 01:17:343462
[email protected]b337cb5b2011-01-23 21:24:053463
[email protected]b8079ae4a2012-12-05 19:56:493464def _CheckPatchFiles(input_api, output_api):
3465 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3466 if f.LocalPath().endswith(('.orig', '.rej'))]
3467 if problems:
3468 return [output_api.PresubmitError(
3469 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033470 else:
3471 return []
[email protected]b8079ae4a2012-12-05 19:56:493472
3473
Kent Tamura5a8755d2017-06-29 23:37:073474def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213475 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3476 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3477 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073478 include_re = input_api.re.compile(
3479 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3480 extension_re = input_api.re.compile(r'\.[a-z]+$')
3481 errors = []
3482 for f in input_api.AffectedFiles():
3483 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3484 continue
3485 found_line_number = None
3486 found_macro = None
3487 for line_num, line in f.ChangedContents():
3488 match = macro_re.search(line)
3489 if match:
3490 found_line_number = line_num
3491 found_macro = match.group(2)
3492 break
3493 if not found_line_number:
3494 continue
3495
3496 found_include = False
3497 for line in f.NewContents():
3498 if include_re.search(line):
3499 found_include = True
3500 break
3501 if found_include:
3502 continue
3503
3504 if not f.LocalPath().endswith('.h'):
3505 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3506 try:
3507 content = input_api.ReadFile(primary_header_path, 'r')
3508 if include_re.search(content):
3509 continue
3510 except IOError:
3511 pass
3512 errors.append('%s:%d %s macro is used without including build/'
3513 'build_config.h.'
3514 % (f.LocalPath(), found_line_number, found_macro))
3515 if errors:
3516 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3517 return []
3518
3519
[email protected]b00342e7f2013-03-26 16:21:543520def _DidYouMeanOSMacro(bad_macro):
3521 try:
3522 return {'A': 'OS_ANDROID',
3523 'B': 'OS_BSD',
3524 'C': 'OS_CHROMEOS',
3525 'F': 'OS_FREEBSD',
3526 'L': 'OS_LINUX',
3527 'M': 'OS_MACOSX',
3528 'N': 'OS_NACL',
3529 'O': 'OS_OPENBSD',
3530 'P': 'OS_POSIX',
3531 'S': 'OS_SOLARIS',
3532 'W': 'OS_WIN'}[bad_macro[3].upper()]
3533 except KeyError:
3534 return ''
3535
3536
3537def _CheckForInvalidOSMacrosInFile(input_api, f):
3538 """Check for sensible looking, totally invalid OS macros."""
3539 preprocessor_statement = input_api.re.compile(r'^\s*#')
3540 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3541 results = []
3542 for lnum, line in f.ChangedContents():
3543 if preprocessor_statement.search(line):
3544 for match in os_macro.finditer(line):
3545 if not match.group(1) in _VALID_OS_MACROS:
3546 good = _DidYouMeanOSMacro(match.group(1))
3547 did_you_mean = ' (did you mean %s?)' % good if good else ''
3548 results.append(' %s:%d %s%s' % (f.LocalPath(),
3549 lnum,
3550 match.group(1),
3551 did_you_mean))
3552 return results
3553
3554
3555def _CheckForInvalidOSMacros(input_api, output_api):
3556 """Check all affected files for invalid OS macros."""
3557 bad_macros = []
tzik3f295992018-12-04 20:32:233558 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473559 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543560 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3561
3562 if not bad_macros:
3563 return []
3564
3565 return [output_api.PresubmitError(
3566 'Possibly invalid OS macro[s] found. Please fix your code\n'
3567 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3568
lliabraa35bab3932014-10-01 12:16:443569
3570def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3571 """Check all affected files for invalid "if defined" macros."""
3572 ALWAYS_DEFINED_MACROS = (
3573 "TARGET_CPU_PPC",
3574 "TARGET_CPU_PPC64",
3575 "TARGET_CPU_68K",
3576 "TARGET_CPU_X86",
3577 "TARGET_CPU_ARM",
3578 "TARGET_CPU_MIPS",
3579 "TARGET_CPU_SPARC",
3580 "TARGET_CPU_ALPHA",
3581 "TARGET_IPHONE_SIMULATOR",
3582 "TARGET_OS_EMBEDDED",
3583 "TARGET_OS_IPHONE",
3584 "TARGET_OS_MAC",
3585 "TARGET_OS_UNIX",
3586 "TARGET_OS_WIN32",
3587 )
3588 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3589 results = []
3590 for lnum, line in f.ChangedContents():
3591 for match in ifdef_macro.finditer(line):
3592 if match.group(1) in ALWAYS_DEFINED_MACROS:
3593 always_defined = ' %s is always defined. ' % match.group(1)
3594 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3595 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3596 lnum,
3597 always_defined,
3598 did_you_mean))
3599 return results
3600
3601
3602def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3603 """Check all affected files for invalid "if defined" macros."""
3604 bad_macros = []
3605 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213606 if f.LocalPath().startswith('third_party/sqlite/'):
3607 continue
lliabraa35bab3932014-10-01 12:16:443608 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3609 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3610
3611 if not bad_macros:
3612 return []
3613
3614 return [output_api.PresubmitError(
3615 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3616 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3617 bad_macros)]
3618
3619
mlamouria82272622014-09-16 18:45:043620def _CheckForIPCRules(input_api, output_api):
3621 """Check for same IPC rules described in
3622 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3623 """
3624 base_pattern = r'IPC_ENUM_TRAITS\('
3625 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3626 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3627
3628 problems = []
3629 for f in input_api.AffectedSourceFiles(None):
3630 local_path = f.LocalPath()
3631 if not local_path.endswith('.h'):
3632 continue
3633 for line_number, line in f.ChangedContents():
3634 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3635 problems.append(
3636 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3637
3638 if problems:
3639 return [output_api.PresubmitPromptWarning(
3640 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3641 else:
3642 return []
3643
[email protected]b00342e7f2013-03-26 16:21:543644
Stephen Martinis97a394142018-06-07 23:06:053645def _CheckForLongPathnames(input_api, output_api):
3646 """Check to make sure no files being submitted have long paths.
3647 This causes issues on Windows.
3648 """
3649 problems = []
3650 for f in input_api.AffectedSourceFiles(None):
3651 local_path = f.LocalPath()
3652 # Windows has a path limit of 260 characters. Limit path length to 200 so
3653 # that we have some extra for the prefix on dev machines and the bots.
3654 if len(local_path) > 200:
3655 problems.append(local_path)
3656
3657 if problems:
3658 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3659 else:
3660 return []
3661
3662
Daniel Bratell8ba52722018-03-02 16:06:143663def _CheckForIncludeGuards(input_api, output_api):
3664 """Check that header files have proper guards against multiple inclusion.
3665 If a file should not have such guards (and it probably should) then it
3666 should include the string "no-include-guard-because-multiply-included".
3667 """
Daniel Bratell6a75baef62018-06-04 10:04:453668 def is_chromium_header_file(f):
3669 # We only check header files under the control of the Chromium
3670 # project. That is, those outside third_party apart from
3671 # third_party/blink.
3672 file_with_path = input_api.os_path.normpath(f.LocalPath())
3673 return (file_with_path.endswith('.h') and
3674 (not file_with_path.startswith('third_party') or
3675 file_with_path.startswith(
3676 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143677
3678 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343679 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143680
3681 errors = []
3682
Daniel Bratell6a75baef62018-06-04 10:04:453683 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143684 guard_name = None
3685 guard_line_number = None
3686 seen_guard_end = False
3687
3688 file_with_path = input_api.os_path.normpath(f.LocalPath())
3689 base_file_name = input_api.os_path.splitext(
3690 input_api.os_path.basename(file_with_path))[0]
3691 upper_base_file_name = base_file_name.upper()
3692
3693 expected_guard = replace_special_with_underscore(
3694 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143695
3696 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573697 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3698 # are too many (1000+) files with slight deviations from the
3699 # coding style. The most important part is that the include guard
3700 # is there, and that it's unique, not the name so this check is
3701 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143702 #
3703 # As code becomes more uniform, this could be made stricter.
3704
3705 guard_name_pattern_list = [
3706 # Anything with the right suffix (maybe with an extra _).
3707 r'\w+_H__?',
3708
Daniel Bratell39b5b062018-05-16 18:09:573709 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143710 r'\w+_h',
3711
3712 # Anything including the uppercase name of the file.
3713 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3714 upper_base_file_name)) + r'\w*',
3715 ]
3716 guard_name_pattern = '|'.join(guard_name_pattern_list)
3717 guard_pattern = input_api.re.compile(
3718 r'#ifndef\s+(' + guard_name_pattern + ')')
3719
3720 for line_number, line in enumerate(f.NewContents()):
3721 if 'no-include-guard-because-multiply-included' in line:
3722 guard_name = 'DUMMY' # To not trigger check outside the loop.
3723 break
3724
3725 if guard_name is None:
3726 match = guard_pattern.match(line)
3727 if match:
3728 guard_name = match.group(1)
3729 guard_line_number = line_number
3730
Daniel Bratell39b5b062018-05-16 18:09:573731 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453732 # don't match the chromium style guide, but new files should
3733 # get it right.
3734 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573735 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143736 errors.append(output_api.PresubmitPromptWarning(
3737 'Header using the wrong include guard name %s' % guard_name,
3738 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573739 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143740 else:
3741 # The line after #ifndef should have a #define of the same name.
3742 if line_number == guard_line_number + 1:
3743 expected_line = '#define %s' % guard_name
3744 if line != expected_line:
3745 errors.append(output_api.PresubmitPromptWarning(
3746 'Missing "%s" for include guard' % expected_line,
3747 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3748 'Expected: %r\nGot: %r' % (expected_line, line)))
3749
3750 if not seen_guard_end and line == '#endif // %s' % guard_name:
3751 seen_guard_end = True
3752 elif seen_guard_end:
3753 if line.strip() != '':
3754 errors.append(output_api.PresubmitPromptWarning(
3755 'Include guard %s not covering the whole file' % (
3756 guard_name), [f.LocalPath()]))
3757 break # Nothing else to check and enough to warn once.
3758
3759 if guard_name is None:
3760 errors.append(output_api.PresubmitPromptWarning(
3761 'Missing include guard %s' % expected_guard,
3762 [f.LocalPath()],
3763 'Missing include guard in %s\n'
3764 'Recommended name: %s\n'
3765 'This check can be disabled by having the string\n'
3766 'no-include-guard-because-multiply-included in the header.' %
3767 (f.LocalPath(), expected_guard)))
3768
3769 return errors
3770
3771
mostynbb639aca52015-01-07 20:31:233772def _CheckForWindowsLineEndings(input_api, output_api):
3773 """Check source code and known ascii text files for Windows style line
3774 endings.
3775 """
earthdok1b5e0ee2015-03-10 15:19:103776 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233777
3778 file_inclusion_pattern = (
3779 known_text_files,
3780 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3781 )
3782
mostynbb639aca52015-01-07 20:31:233783 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533784 source_file_filter = lambda f: input_api.FilterSourceFile(
3785 f, white_list=file_inclusion_pattern, black_list=None)
3786 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503787 include_file = False
3788 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233789 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503790 include_file = True
3791 if include_file:
3792 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233793
3794 if problems:
3795 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3796 'these files to contain Windows style line endings?\n' +
3797 '\n'.join(problems))]
3798
3799 return []
3800
3801
Vaclav Brozekd5de76a2018-03-17 07:57:503802def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133803 """Checks that all source files use SYSLOG properly."""
3804 syslog_files = []
3805 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563806 for line_number, line in f.ChangedContents():
3807 if 'SYSLOG' in line:
3808 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3809
pastarmovj89f7ee12016-09-20 14:58:133810 if syslog_files:
3811 return [output_api.PresubmitPromptWarning(
3812 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3813 ' calls.\nFiles to check:\n', items=syslog_files)]
3814 return []
3815
3816
[email protected]1f7b4172010-01-28 01:17:343817def CheckChangeOnUpload(input_api, output_api):
3818 results = []
3819 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473820 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283821 results.extend(
jam93a6ee792017-02-08 23:59:223822 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193823 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223824 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133825 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163826 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533827 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193828 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543829 return results
[email protected]ca8d1982009-02-19 16:33:123830
3831
[email protected]1bfb8322014-04-23 01:02:413832def GetTryServerMasterForBot(bot):
3833 """Returns the Try Server master for the given bot.
3834
[email protected]0bb112362014-07-26 04:38:323835 It tries to guess the master from the bot name, but may still fail
3836 and return None. There is no longer a default master.
3837 """
3838 # Potentially ambiguous bot names are listed explicitly.
3839 master_map = {
tandriie5587792016-07-14 00:34:503840 'chromium_presubmit': 'master.tryserver.chromium.linux',
3841 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413842 }
[email protected]0bb112362014-07-26 04:38:323843 master = master_map.get(bot)
3844 if not master:
wnwen4fbaab82016-05-25 12:54:363845 if 'android' in bot:
tandriie5587792016-07-14 00:34:503846 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363847 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503848 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323849 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503850 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323851 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503852 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323853 return master
[email protected]1bfb8322014-04-23 01:02:413854
3855
[email protected]ca8d1982009-02-19 16:33:123856def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543857 results = []
[email protected]1f7b4172010-01-28 01:17:343858 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573859 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543860 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273861 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343862 input_api,
3863 output_api,
[email protected]2fdd1f362013-01-16 03:56:033864 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273865
jam93a6ee792017-02-08 23:59:223866 results.extend(
3867 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543868 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3869 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413870 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3871 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543872 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143873
3874
3875def _CheckTranslationScreenshots(input_api, output_api):
3876 PART_FILE_TAG = "part"
3877 import os
3878 import sys
3879 from io import StringIO
3880
3881 try:
3882 old_sys_path = sys.path
3883 sys.path = sys.path + [input_api.os_path.join(
3884 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3885 import grit.grd_reader
3886 import grit.node.message
3887 import grit.util
3888 finally:
3889 sys.path = old_sys_path
3890
3891 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3892 """Load the grd file and return a dict of message ids to messages.
3893
3894 Ignores any nested grdp files pointed by <part> tag.
3895 """
3896 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3897 stop_after=None, first_ids_file=None,
3898 debug=False, defines=None,
3899 tags_to_ignore=set([PART_FILE_TAG]))
3900 return {
3901 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3902 grit.node.message.MessageNode)
3903 }
3904
3905 def _GetGrdpMessagesFromString(grdp_string):
3906 """Parses the contents of a grdp file given in grdp_string.
3907
3908 grd_reader can't parse grdp files directly. Instead, this creates a
3909 temporary directory with a grd file pointing to the grdp file, and loads the
3910 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3911 """
3912 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3913 <grit latest_public_release="1" current_release="1">
3914 <release seq="1">
3915 <messages>
3916 <part file="sub.grdp" />
3917 </messages>
3918 </release>
3919 </grit>
3920 """
3921 with grit.util.TempDir({'main.grd': WRAPPER,
3922 'sub.grdp': grdp_string}) as temp_dir:
3923 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3924
3925 new_or_added_paths = set(f.LocalPath()
3926 for f in input_api.AffectedFiles()
3927 if (f.Action() == 'A' or f.Action() == 'M'))
3928 removed_paths = set(f.LocalPath()
3929 for f in input_api.AffectedFiles(include_deletes=True)
3930 if f.Action() == 'D')
3931
3932 affected_grds = [f for f in input_api.AffectedFiles()
3933 if (f.LocalPath().endswith('.grd') or
3934 f.LocalPath().endswith('.grdp'))]
3935 affected_png_paths = [f.AbsoluteLocalPath()
3936 for f in input_api.AffectedFiles()
3937 if (f.LocalPath().endswith('.png'))]
3938
3939 # Check for screenshots. Developers can upload screenshots using
3940 # tools/translation/upload_screenshots.py which finds and uploads
3941 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3942 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3943 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3944 #
3945 # The logic here is as follows:
3946 #
3947 # - If the CL has a .png file under the screenshots directory for a grd
3948 # file, warn the developer. Actual images should never be checked into the
3949 # Chrome repo.
3950 #
3951 # - If the CL contains modified or new messages in grd files and doesn't
3952 # contain the corresponding .sha1 files, warn the developer to add images
3953 # and upload them via tools/translation/upload_screenshots.py.
3954 #
3955 # - If the CL contains modified or new messages in grd files and the
3956 # corresponding .sha1 files, everything looks good.
3957 #
3958 # - If the CL contains removed messages in grd files but the corresponding
3959 # .sha1 files aren't removed, warn the developer to remove them.
3960 unnecessary_screenshots = []
3961 missing_sha1 = []
3962 unnecessary_sha1_files = []
3963
3964
3965 def _CheckScreenshotAdded(screenshots_dir, message_id):
3966 sha1_path = input_api.os_path.join(
3967 screenshots_dir, message_id + '.png.sha1')
3968 if sha1_path not in new_or_added_paths:
3969 missing_sha1.append(sha1_path)
3970
3971
3972 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3973 sha1_path = input_api.os_path.join(
3974 screenshots_dir, message_id + '.png.sha1')
3975 if sha1_path not in removed_paths:
3976 unnecessary_sha1_files.append(sha1_path)
3977
3978
3979 for f in affected_grds:
3980 file_path = f.LocalPath()
3981 old_id_to_msg_map = {}
3982 new_id_to_msg_map = {}
3983 if file_path.endswith('.grdp'):
3984 if f.OldContents():
3985 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393986 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143987 if f.NewContents():
3988 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393989 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143990 else:
3991 if f.OldContents():
3992 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393993 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143994 if f.NewContents():
3995 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393996 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143997
3998 # Compute added, removed and modified message IDs.
3999 old_ids = set(old_id_to_msg_map)
4000 new_ids = set(new_id_to_msg_map)
4001 added_ids = new_ids - old_ids
4002 removed_ids = old_ids - new_ids
4003 modified_ids = set([])
4004 for key in old_ids.intersection(new_ids):
4005 if (old_id_to_msg_map[key].FormatXml()
4006 != new_id_to_msg_map[key].FormatXml()):
4007 modified_ids.add(key)
4008
4009 grd_name, ext = input_api.os_path.splitext(
4010 input_api.os_path.basename(file_path))
4011 screenshots_dir = input_api.os_path.join(
4012 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
4013
4014 # Check the screenshot directory for .png files. Warn if there is any.
4015 for png_path in affected_png_paths:
4016 if png_path.startswith(screenshots_dir):
4017 unnecessary_screenshots.append(png_path)
4018
4019 for added_id in added_ids:
4020 _CheckScreenshotAdded(screenshots_dir, added_id)
4021
4022 for modified_id in modified_ids:
4023 _CheckScreenshotAdded(screenshots_dir, modified_id)
4024
4025 for removed_id in removed_ids:
4026 _CheckScreenshotRemoved(screenshots_dir, removed_id)
4027
4028 results = []
4029 if unnecessary_screenshots:
4030 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394031 'Do not include actual screenshots in the changelist. Run '
4032 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144033 sorted(unnecessary_screenshots)))
4034
4035 if missing_sha1:
4036 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394037 'You are adding or modifying UI strings.\n'
4038 'To ensure the best translations, take screenshots of the relevant UI '
4039 '(https://g.co/chrome/translation) and add these files to your '
4040 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144041
4042 if unnecessary_sha1_files:
4043 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:394044 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144045 sorted(unnecessary_sha1_files)))
4046
4047 return results