blob: 0508eda5cf26157692c7566b20cf0b7844d31bb2 [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,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0454 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0456 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0458 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 (
thomasandersone7caaa9b2017-03-29 19:22:53212 r'\bNULL\b',
213 (
214 'New code should not use NULL. Use nullptr instead.',
215 ),
216 True,
217 (),
218 ),
Antonio Gomes07300d02019-03-13 20:59:57219 # Make sure that gtest's FRIEND_TEST() macro is not used; the
220 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
221 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
Egor Paskoce145c42018-09-28 19:31:04241 r"^ui[\\/]gl[\\/].*\.cc$",
242 r"^media[\\/]gpu[\\/].*\.cc$",
243 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
Egor Paskoce145c42018-09-28 19:31:04336 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
tzik3f295992018-12-04 20:32:23346 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04347 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41348 ),
jame2d1a952016-04-02 00:27:10349 ),
fdorayc4ac18d2017-05-01 21:39:59350 (
Gabriel Charette7cc6c432018-04-25 20:52:02351 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59352 (
353 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
354 ),
355 False,
356 (),
357 ),
358 (
Gabriel Charette7cc6c432018-04-25 20:52:02359 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59360 (
361 'Consider using THREAD_CHECKER macros instead of the class directly.',
362 ),
363 False,
364 (),
365 ),
dbeamb6f4fde2017-06-15 04:03:06366 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06367 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
368 (
369 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
370 'deprecated (http://crbug.com/634507). Please avoid converting away',
371 'from the Time types in Chromium code, especially if any math is',
372 'being done on time values. For interfacing with platform/library',
373 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
374 'type converter methods instead. For faking TimeXXX values (for unit',
375 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
376 'other use cases, please contact base/time/OWNERS.',
377 ),
378 False,
379 (),
380 ),
381 (
dbeamb6f4fde2017-06-15 04:03:06382 'CallJavascriptFunctionUnsafe',
383 (
384 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
385 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
386 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
387 ),
388 False,
389 (
Egor Paskoce145c42018-09-28 19:31:04390 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
391 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
392 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06393 ),
394 ),
dskiba1474c2bfd62017-07-20 02:19:24395 (
396 'leveldb::DB::Open',
397 (
398 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
399 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
400 "Chrome's tracing, making their memory usage visible.",
401 ),
402 True,
403 (
404 r'^third_party/leveldatabase/.*\.(cc|h)$',
405 ),
Gabriel Charette0592c3a2017-07-26 12:02:04406 ),
407 (
Chris Mumfordc38afb62017-10-09 17:55:08408 'leveldb::NewMemEnv',
409 (
410 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58411 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
412 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08413 ),
414 True,
415 (
416 r'^third_party/leveldatabase/.*\.(cc|h)$',
417 ),
418 ),
419 (
Gabriel Charetted9839bc2017-07-29 14:17:47420 'RunLoop::QuitCurrent',
421 (
Robert Liao64b7ab22017-08-04 23:03:43422 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
423 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47424 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41425 False,
Gabriel Charetted9839bc2017-07-29 14:17:47426 (),
Gabriel Charettea44975052017-08-21 23:14:04427 ),
428 (
429 'base::ScopedMockTimeMessageLoopTaskRunner',
430 (
Gabriel Charette87cc1af2018-04-25 20:52:51431 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
432 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
433 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
434 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
435 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04436 ),
Gabriel Charette87cc1af2018-04-25 20:52:51437 False,
Gabriel Charettea44975052017-08-21 23:14:04438 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57439 ),
440 (
441 r'std::regex',
442 (
443 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02444 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57445 ),
446 True,
447 (),
Francois Doray43670e32017-09-27 12:40:38448 ),
449 (
450 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
451 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
452 (
453 'Use the new API in base/threading/thread_restrictions.h.',
454 ),
Gabriel Charette04b138f2018-08-06 00:03:22455 False,
Francois Doray43670e32017-09-27 12:40:38456 (),
457 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38458 (
459 r'/\bbase::Bind\(',
460 (
Gabriel Charette147335ea2018-03-22 15:59:19461 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02462 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38463 ),
464 False,
465 (),
466 ),
467 (
468 r'/\bbase::Callback<',
469 (
Gabriel Charette147335ea2018-03-22 15:59:19470 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02471 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38472 ),
473 False,
474 (),
475 ),
476 (
477 r'/\bbase::Closure\b',
478 (
Gabriel Charette147335ea2018-03-22 15:59:19479 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02480 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38481 ),
482 False,
483 (),
484 ),
Victor Costan3653df62018-02-08 21:38:16485 (
Gabriel Charette147335ea2018-03-22 15:59:19486 r'RunMessageLoop',
487 (
488 'RunMessageLoop is deprecated, use RunLoop instead.',
489 ),
490 False,
491 (),
492 ),
493 (
494 r'RunThisRunLoop',
495 (
496 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
497 ),
498 False,
499 (),
500 ),
501 (
502 r'RunAllPendingInMessageLoop()',
503 (
504 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
505 "if you're convinced you need this.",
506 ),
507 False,
508 (),
509 ),
510 (
511 r'RunAllPendingInMessageLoop(BrowserThread',
512 (
513 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
514 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
515 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
516 'async events instead of flushing threads.',
517 ),
518 False,
519 (),
520 ),
521 (
522 r'MessageLoopRunner',
523 (
524 'MessageLoopRunner is deprecated, use RunLoop instead.',
525 ),
526 False,
527 (),
528 ),
529 (
530 r'GetDeferredQuitTaskForRunLoop',
531 (
532 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
533 "gab@ if you found a use case where this is the only solution.",
534 ),
535 False,
536 (),
537 ),
538 (
Victor Costan3653df62018-02-08 21:38:16539 'sqlite3_initialize',
540 (
541 'Instead of sqlite3_initialize, depend on //sql, ',
542 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
543 ),
544 True,
545 (
546 r'^sql/initialization\.(cc|h)$',
547 r'^third_party/sqlite/.*\.(c|cc|h)$',
548 ),
549 ),
Matt Menke7f520a82018-03-28 21:38:37550 (
551 'net::URLFetcher',
552 (
553 'net::URLFetcher should no longer be used in content embedders. ',
554 'Instead, use network::SimpleURLLoader instead, which supports ',
555 'an out-of-process network stack. ',
556 'net::URLFetcher may still be used in binaries that do not embed',
557 'content.',
558 ),
Matt Menke59716d02018-04-05 12:45:53559 False,
Matt Menke7f520a82018-03-28 21:38:37560 (
Egor Paskoce145c42018-09-28 19:31:04561 r'^ios[\\/].*\.(cc|h)$',
562 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37563 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04564 r'^net[\\/].*\.(cc|h)$',
565 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37566 ),
567 ),
jdoerried7d10ab2018-04-27 10:46:13568 (
tzik5de2157f2018-05-08 03:42:47569 r'std::random_shuffle',
570 (
571 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
572 'base::RandomShuffle instead.'
573 ),
574 True,
575 (),
576 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24577 (
578 'ios/web/public/test/http_server',
579 (
580 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
581 ),
582 False,
583 (),
584 ),
Robert Liao764c9492019-01-24 18:46:28585 (
586 'GetAddressOf',
587 (
588 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
589 'implicated in a few leaks. Use operator& instead.'
590 ),
591 True,
592 (),
593 ),
Antonio Gomes07300d02019-03-13 20:59:57594 (
595 'DEFINE_TYPE_CASTS',
596 (
597 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
598 '//third_party/blink/renderer/platform/casting.h.'
599 ),
600 True,
601 (
602 r'^third_party/blink/renderer/.*\.(cc|h)$',
603 ),
604 ),
[email protected]127f18ec2012-06-16 05:05:59605)
606
wnwenbdc444e2016-05-25 13:44:15607
mlamouria82272622014-09-16 18:45:04608_IPC_ENUM_TRAITS_DEPRECATED = (
609 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50610 'See http://www.chromium.org/Home/chromium-security/education/'
611 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04612
Stephen Martinis97a394142018-06-07 23:06:05613_LONG_PATH_ERROR = (
614 'Some files included in this CL have file names that are too long (> 200'
615 ' characters). If committed, these files will cause issues on Windows. See'
616 ' https://crbug.com/612667 for more details.'
617)
618
Shenghua Zhangbfaa38b82017-11-16 21:58:02619_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04620 r".*[\\/]BuildHooksAndroidImpl\.java",
621 r".*[\\/]LicenseContentProvider\.java",
622 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28623 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02624]
[email protected]127f18ec2012-06-16 05:05:59625
Sean Kau46e29bc2017-08-28 16:31:16626# These paths contain test data and other known invalid JSON files.
627_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04628 r'test[\\/]data[\\/]',
629 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
630 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04631 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43632 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16633]
634
635
[email protected]b00342e7f2013-03-26 16:21:54636_VALID_OS_MACROS = (
637 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08638 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54639 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12640 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54641 'OS_BSD',
642 'OS_CAT', # For testing.
643 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04644 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54645 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37646 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54647 'OS_IOS',
648 'OS_LINUX',
649 'OS_MACOSX',
650 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21651 'OS_NACL_NONSFI',
652 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12653 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54654 'OS_OPENBSD',
655 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37656 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54657 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54658 'OS_WIN',
659)
660
661
agrievef32bcc72016-04-04 14:57:40662_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39663 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36664 'base/android/jni_generator/jni_generator.pydeps',
665 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:22666 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36667 'build/android/gyp/aar.pydeps',
668 'build/android/gyp/aidl.pydeps',
669 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38670 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36671 'build/android/gyp/bytecode_processor.pydeps',
672 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57673 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36674 'build/android/gyp/create_bundle_wrapper_script.pydeps',
675 'build/android/gyp/copy_ex.pydeps',
676 'build/android/gyp/create_app_bundle.pydeps',
677 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36678 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22679 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36680 'build/android/gyp/create_stack_script.pydeps',
681 'build/android/gyp/create_test_runner_script.pydeps',
682 'build/android/gyp/create_tool_wrapper.pydeps',
683 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59684 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36685 'build/android/gyp/dex.pydeps',
686 'build/android/gyp/dist_aar.pydeps',
687 'build/android/gyp/emma_instr.pydeps',
688 'build/android/gyp/filter_zip.pydeps',
689 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36690 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36691 'build/android/gyp/ijar.pydeps',
692 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26693 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36694 'build/android/gyp/javac.pydeps',
695 'build/android/gyp/jinja_template.pydeps',
696 'build/android/gyp/lint.pydeps',
697 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36698 'build/android/gyp/merge_manifest.pydeps',
699 'build/android/gyp/prepare_resources.pydeps',
700 'build/android/gyp/proguard.pydeps',
701 'build/android/gyp/write_build_config.pydeps',
702 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56703 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36704 'build/android/incremental_install/generate_android_manifest.pydeps',
705 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22706 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40707 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04708 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36709 'build/protoc_java.pydeps',
Sam Maier3599daa2018-11-26 18:02:59710 ('build/secondary/third_party/android_platform/'
711 'development/scripts/stack.pydeps'),
agrieve732db3a2016-04-26 19:18:19712 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40713]
714
wnwenbdc444e2016-05-25 13:44:15715
agrievef32bcc72016-04-04 14:57:40716_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40717 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29718 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22719 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40720]
721
wnwenbdc444e2016-05-25 13:44:15722
agrievef32bcc72016-04-04 14:57:40723_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
724
725
Eric Boren6fd2b932018-01-25 15:05:08726# Bypass the AUTHORS check for these accounts.
727_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29728 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
729 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08730 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32731 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59732 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45733 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59734 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22735 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04736 ) | set('%[email protected]' % s
737 for s in ('chromium-autoroll',)
738 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30739 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08740
741
[email protected]55459852011-08-10 15:17:19742def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
743 """Attempts to prevent use of functions intended only for testing in
744 non-testing code. For now this is just a best-effort implementation
745 that ignores header files and may have some false positives. A
746 better implementation would probably need a proper C++ parser.
747 """
748 # We only scan .cc files and the like, as the declaration of
749 # for-testing functions in header files are hard to distinguish from
750 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49751 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19752
jochenc0d4808c2015-07-27 09:25:42753 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19754 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09755 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19756 exclusion_pattern = input_api.re.compile(
757 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
758 base_function_pattern, base_function_pattern))
759
760 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44761 black_list = (_EXCLUDED_PATHS +
762 _TEST_CODE_EXCLUDED_PATHS +
763 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19764 return input_api.FilterSourceFile(
765 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49766 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19767 black_list=black_list)
768
769 problems = []
770 for f in input_api.AffectedSourceFiles(FilterFile):
771 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24772 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03773 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46774 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03775 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19776 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03777 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19778
779 if problems:
[email protected]f7051d52013-04-02 18:31:42780 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03781 else:
782 return []
[email protected]55459852011-08-10 15:17:19783
784
Vaclav Brozek7dbc28c2018-03-27 08:35:23785def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
786 """This is a simplified version of
787 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
788 """
789 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
790 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
791 name_pattern = r'ForTest(s|ing)?'
792 # Describes an occurrence of "ForTest*" inside a // comment.
793 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
794 # Catch calls.
795 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
796 # Ignore definitions. (Comments are ignored separately.)
797 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
798
799 problems = []
800 sources = lambda x: input_api.FilterSourceFile(
801 x,
802 black_list=(('(?i).*test', r'.*\/junit\/')
803 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49804 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23805 )
806 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
807 local_path = f.LocalPath()
808 is_inside_javadoc = False
809 for line_number, line in f.ChangedContents():
810 if is_inside_javadoc and javadoc_end_re.search(line):
811 is_inside_javadoc = False
812 if not is_inside_javadoc and javadoc_start_re.search(line):
813 is_inside_javadoc = True
814 if is_inside_javadoc:
815 continue
816 if (inclusion_re.search(line) and
817 not comment_re.search(line) and
818 not exclusion_re.search(line)):
819 problems.append(
820 '%s:%d\n %s' % (local_path, line_number, line.strip()))
821
822 if problems:
823 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
824 else:
825 return []
826
827
[email protected]10689ca2011-09-02 02:31:54828def _CheckNoIOStreamInHeaders(input_api, output_api):
829 """Checks to make sure no .h files include <iostream>."""
830 files = []
831 pattern = input_api.re.compile(r'^#include\s*<iostream>',
832 input_api.re.MULTILINE)
833 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
834 if not f.LocalPath().endswith('.h'):
835 continue
836 contents = input_api.ReadFile(f)
837 if pattern.search(contents):
838 files.append(f)
839
840 if len(files):
yolandyandaabc6d2016-04-18 18:29:39841 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06842 'Do not #include <iostream> in header files, since it inserts static '
843 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54844 '#include <ostream>. See http://crbug.com/94794',
845 files) ]
846 return []
847
Danil Chapovalov3518f362018-08-11 16:13:43848def _CheckNoStrCatRedefines(input_api, output_api):
849 """Checks no windows headers with StrCat redefined are included directly."""
850 files = []
851 pattern_deny = input_api.re.compile(
852 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
853 input_api.re.MULTILINE)
854 pattern_allow = input_api.re.compile(
855 r'^#include\s"base/win/windows_defines.inc"',
856 input_api.re.MULTILINE)
857 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
858 contents = input_api.ReadFile(f)
859 if pattern_deny.search(contents) and not pattern_allow.search(contents):
860 files.append(f.LocalPath())
861
862 if len(files):
863 return [output_api.PresubmitError(
864 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
865 'directly since they pollute code with StrCat macro. Instead, '
866 'include matching header from base/win. See http://crbug.com/856536',
867 files) ]
868 return []
869
[email protected]10689ca2011-09-02 02:31:54870
[email protected]72df4e782012-06-21 16:28:18871def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52872 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18873 problems = []
874 for f in input_api.AffectedFiles():
875 if (not f.LocalPath().endswith(('.cc', '.mm'))):
876 continue
877
878 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04879 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18880 problems.append(' %s:%d' % (f.LocalPath(), line_num))
881
882 if not problems:
883 return []
884 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
885 '\n'.join(problems))]
886
Dominic Battre033531052018-09-24 15:45:34887def _CheckNoDISABLETypoInTests(input_api, output_api):
888 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
889
890 This test warns if somebody tries to disable a test with the DISABLE_ prefix
891 instead of DISABLED_. To filter false positives, reports are only generated
892 if a corresponding MAYBE_ line exists.
893 """
894 problems = []
895
896 # The following two patterns are looked for in tandem - is a test labeled
897 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
898 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
899 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
900
901 # This is for the case that a test is disabled on all platforms.
902 full_disable_pattern = input_api.re.compile(
903 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
904 input_api.re.MULTILINE)
905
Katie Df13948e2018-09-25 07:33:44906 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34907 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
908 continue
909
910 # Search for MABYE_, DISABLE_ pairs.
911 disable_lines = {} # Maps of test name to line number.
912 maybe_lines = {}
913 for line_num, line in f.ChangedContents():
914 disable_match = disable_pattern.search(line)
915 if disable_match:
916 disable_lines[disable_match.group(1)] = line_num
917 maybe_match = maybe_pattern.search(line)
918 if maybe_match:
919 maybe_lines[maybe_match.group(1)] = line_num
920
921 # Search for DISABLE_ occurrences within a TEST() macro.
922 disable_tests = set(disable_lines.keys())
923 maybe_tests = set(maybe_lines.keys())
924 for test in disable_tests.intersection(maybe_tests):
925 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
926
927 contents = input_api.ReadFile(f)
928 full_disable_match = full_disable_pattern.search(contents)
929 if full_disable_match:
930 problems.append(' %s' % f.LocalPath())
931
932 if not problems:
933 return []
934 return [
935 output_api.PresubmitPromptWarning(
936 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
937 '\n'.join(problems))
938 ]
939
[email protected]72df4e782012-06-21 16:28:18940
danakj61c1aa22015-10-26 19:55:52941def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57942 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52943 errors = []
944 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
945 input_api.re.MULTILINE)
946 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
947 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
948 continue
949 for lnum, line in f.ChangedContents():
950 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17951 errors.append(output_api.PresubmitError(
952 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57953 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17954 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52955 return errors
956
957
mcasasb7440c282015-02-04 14:52:19958def _FindHistogramNameInLine(histogram_name, line):
959 """Tries to find a histogram name or prefix in a line."""
960 if not "affected-histogram" in line:
961 return histogram_name in line
962 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
963 # the histogram_name.
964 if not '"' in line:
965 return False
966 histogram_prefix = line.split('\"')[1]
967 return histogram_prefix in histogram_name
968
969
970def _CheckUmaHistogramChanges(input_api, output_api):
971 """Check that UMA histogram names in touched lines can still be found in other
972 lines of the patch or in histograms.xml. Note that this check would not catch
973 the reverse: changes in histograms.xml not matched in the code itself."""
974 touched_histograms = []
975 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47976 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
977 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
978 name_pattern = r'"(.*?)"'
979 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
980 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
981 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
982 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
983 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17984 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19985 for f in input_api.AffectedFiles():
986 # If histograms.xml itself is modified, keep the modified lines for later.
987 if f.LocalPath().endswith(('histograms.xml')):
988 histograms_xml_modifications = f.ChangedContents()
989 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47990 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
991 single_line_re = single_line_c_re
992 split_line_prefix_re = split_line_c_prefix_re
993 elif f.LocalPath().endswith(('java')):
994 single_line_re = single_line_java_re
995 split_line_prefix_re = split_line_java_prefix_re
996 else:
mcasasb7440c282015-02-04 14:52:19997 continue
998 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17999 if last_line_matched_prefix:
1000 suffix_found = split_line_suffix_re.search(line)
1001 if suffix_found :
1002 touched_histograms.append([suffix_found.group(1), f, line_num])
1003 last_line_matched_prefix = False
1004 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061005 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191006 if found:
1007 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171008 continue
1009 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191010
1011 # Search for the touched histogram names in the local modifications to
1012 # histograms.xml, and, if not found, on the base histograms.xml file.
1013 unmatched_histograms = []
1014 for histogram_info in touched_histograms:
1015 histogram_name_found = False
1016 for line_num, line in histograms_xml_modifications:
1017 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1018 if histogram_name_found:
1019 break
1020 if not histogram_name_found:
1021 unmatched_histograms.append(histogram_info)
1022
eromanb90c82e7e32015-04-01 15:13:491023 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191024 problems = []
1025 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491026 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191027 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451028 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191029 histogram_name_found = False
1030 for line in histograms_xml:
1031 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1032 if histogram_name_found:
1033 break
1034 if not histogram_name_found:
1035 problems.append(' [%s:%d] %s' %
1036 (f.LocalPath(), line_num, histogram_name))
1037
1038 if not problems:
1039 return []
1040 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1041 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491042 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191043
wnwenbdc444e2016-05-25 13:44:151044
yolandyandaabc6d2016-04-18 18:29:391045def _CheckFlakyTestUsage(input_api, output_api):
1046 """Check that FlakyTest annotation is our own instead of the android one"""
1047 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1048 files = []
1049 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1050 if f.LocalPath().endswith('Test.java'):
1051 if pattern.search(input_api.ReadFile(f)):
1052 files.append(f)
1053 if len(files):
1054 return [output_api.PresubmitError(
1055 'Use org.chromium.base.test.util.FlakyTest instead of '
1056 'android.test.FlakyTest',
1057 files)]
1058 return []
mcasasb7440c282015-02-04 14:52:191059
wnwenbdc444e2016-05-25 13:44:151060
[email protected]8ea5d4b2011-09-13 21:49:221061def _CheckNoNewWStrings(input_api, output_api):
1062 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271063 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221064 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201065 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571066 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341067 '/win/' in f.LocalPath() or
1068 'chrome_elf' in f.LocalPath() or
1069 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201070 continue
[email protected]8ea5d4b2011-09-13 21:49:221071
[email protected]a11dbe9b2012-08-07 01:32:581072 allowWString = False
[email protected]b5c24292011-11-28 14:38:201073 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581074 if 'presubmit: allow wstring' in line:
1075 allowWString = True
1076 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271077 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581078 allowWString = False
1079 else:
1080 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221081
[email protected]55463aa62011-10-12 00:48:271082 if not problems:
1083 return []
1084 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581085 ' If you are calling a cross-platform API that accepts a wstring, '
1086 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271087 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221088
1089
[email protected]2a8ac9c2011-10-19 17:20:441090def _CheckNoDEPSGIT(input_api, output_api):
1091 """Make sure .DEPS.git is never modified manually."""
1092 if any(f.LocalPath().endswith('.DEPS.git') for f in
1093 input_api.AffectedFiles()):
1094 return [output_api.PresubmitError(
1095 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1096 'automated system based on what\'s in DEPS and your changes will be\n'
1097 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501098 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1099 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441100 'for more information')]
1101 return []
1102
1103
tandriief664692014-09-23 14:51:471104def _CheckValidHostsInDEPS(input_api, output_api):
1105 """Checks that DEPS file deps are from allowed_hosts."""
1106 # Run only if DEPS file has been modified to annoy fewer bystanders.
1107 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1108 return []
1109 # Outsource work to gclient verify
1110 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201111 input_api.subprocess.check_output(['gclient', 'verify'],
1112 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471113 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201114 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471115 return [output_api.PresubmitError(
1116 'DEPS file must have only git dependencies.',
1117 long_text=error.output)]
1118
1119
[email protected]127f18ec2012-06-16 05:05:591120def _CheckNoBannedFunctions(input_api, output_api):
1121 """Make sure that banned functions are not used."""
1122 warnings = []
1123 errors = []
1124
wnwenbdc444e2016-05-25 13:44:151125 def IsBlacklisted(affected_file, blacklist):
1126 local_path = affected_file.LocalPath()
1127 for item in blacklist:
1128 if input_api.re.match(item, local_path):
1129 return True
1130 return False
1131
Sylvain Defresnea8b73d252018-02-28 15:45:541132 def IsIosObcjFile(affected_file):
1133 local_path = affected_file.LocalPath()
1134 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1135 return False
1136 basename = input_api.os_path.basename(local_path)
1137 if 'ios' in basename.split('_'):
1138 return True
1139 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1140 if sep and 'ios' in local_path.split(sep):
1141 return True
1142 return False
1143
wnwenbdc444e2016-05-25 13:44:151144 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1145 matched = False
1146 if func_name[0:1] == '/':
1147 regex = func_name[1:]
1148 if input_api.re.search(regex, line):
1149 matched = True
1150 elif func_name in line:
dchenge07de812016-06-20 19:27:171151 matched = True
wnwenbdc444e2016-05-25 13:44:151152 if matched:
dchenge07de812016-06-20 19:27:171153 problems = warnings
wnwenbdc444e2016-05-25 13:44:151154 if error:
dchenge07de812016-06-20 19:27:171155 problems = errors
wnwenbdc444e2016-05-25 13:44:151156 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1157 for message_line in message:
1158 problems.append(' %s' % message_line)
1159
Eric Stevensona9a980972017-09-23 00:04:411160 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1161 for f in input_api.AffectedFiles(file_filter=file_filter):
1162 for line_num, line in f.ChangedContents():
1163 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1164 CheckForMatch(f, line_num, line, func_name, message, error)
1165
[email protected]127f18ec2012-06-16 05:05:591166 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1167 for f in input_api.AffectedFiles(file_filter=file_filter):
1168 for line_num, line in f.ChangedContents():
1169 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151170 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591171
Sylvain Defresnea8b73d252018-02-28 15:45:541172 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1173 for line_num, line in f.ChangedContents():
1174 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1175 CheckForMatch(f, line_num, line, func_name, message, error)
1176
[email protected]127f18ec2012-06-16 05:05:591177 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1178 for f in input_api.AffectedFiles(file_filter=file_filter):
1179 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491180 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491181 if IsBlacklisted(f, excluded_paths):
1182 continue
wnwenbdc444e2016-05-25 13:44:151183 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591184
1185 result = []
1186 if (warnings):
1187 result.append(output_api.PresubmitPromptWarning(
1188 'Banned functions were used.\n' + '\n'.join(warnings)))
1189 if (errors):
1190 result.append(output_api.PresubmitError(
1191 'Banned functions were used.\n' + '\n'.join(errors)))
1192 return result
1193
1194
[email protected]6c063c62012-07-11 19:11:061195def _CheckNoPragmaOnce(input_api, output_api):
1196 """Make sure that banned functions are not used."""
1197 files = []
1198 pattern = input_api.re.compile(r'^#pragma\s+once',
1199 input_api.re.MULTILINE)
1200 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1201 if not f.LocalPath().endswith('.h'):
1202 continue
1203 contents = input_api.ReadFile(f)
1204 if pattern.search(contents):
1205 files.append(f)
1206
1207 if files:
1208 return [output_api.PresubmitError(
1209 'Do not use #pragma once in header files.\n'
1210 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1211 files)]
1212 return []
1213
[email protected]127f18ec2012-06-16 05:05:591214
[email protected]e7479052012-09-19 00:26:121215def _CheckNoTrinaryTrueFalse(input_api, output_api):
1216 """Checks to make sure we don't introduce use of foo ? true : false."""
1217 problems = []
1218 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1219 for f in input_api.AffectedFiles():
1220 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1221 continue
1222
1223 for line_num, line in f.ChangedContents():
1224 if pattern.match(line):
1225 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1226
1227 if not problems:
1228 return []
1229 return [output_api.PresubmitPromptWarning(
1230 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1231 '\n'.join(problems))]
1232
1233
[email protected]55f9f382012-07-31 11:02:181234def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281235 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181236 change. Breaking - rules is an error, breaking ! rules is a
1237 warning.
1238 """
mohan.reddyf21db962014-10-16 12:26:471239 import sys
[email protected]55f9f382012-07-31 11:02:181240 # We need to wait until we have an input_api object and use this
1241 # roundabout construct to import checkdeps because this file is
1242 # eval-ed and thus doesn't have __file__.
1243 original_sys_path = sys.path
1244 try:
1245 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471246 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181247 import checkdeps
1248 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241249 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281250 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181251 from rules import Rule
1252 finally:
1253 # Restore sys.path to what it was before.
1254 sys.path = original_sys_path
1255
1256 added_includes = []
rhalavati08acd232017-04-03 07:23:281257 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241258 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181259 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281260 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501261 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081262 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281263 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501264 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081265 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241266 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501267 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081268 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181269
[email protected]26385172013-05-09 23:11:351270 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181271
1272 error_descriptions = []
1273 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281274 error_subjects = set()
1275 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181276 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1277 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081278 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181279 description_with_path = '%s\n %s' % (path, rule_description)
1280 if rule_type == Rule.DISALLOW:
1281 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281282 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181283 else:
1284 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281285 warning_subjects.add("#includes")
1286
1287 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1288 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081289 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281290 description_with_path = '%s\n %s' % (path, rule_description)
1291 if rule_type == Rule.DISALLOW:
1292 error_descriptions.append(description_with_path)
1293 error_subjects.add("imports")
1294 else:
1295 warning_descriptions.append(description_with_path)
1296 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181297
Jinsuk Kim5a092672017-10-24 22:42:241298 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021299 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081300 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241301 description_with_path = '%s\n %s' % (path, rule_description)
1302 if rule_type == Rule.DISALLOW:
1303 error_descriptions.append(description_with_path)
1304 error_subjects.add("imports")
1305 else:
1306 warning_descriptions.append(description_with_path)
1307 warning_subjects.add("imports")
1308
[email protected]55f9f382012-07-31 11:02:181309 results = []
1310 if error_descriptions:
1311 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281312 'You added one or more %s that violate checkdeps rules.'
1313 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181314 error_descriptions))
1315 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421316 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281317 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181318 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281319 '%s? See relevant DEPS file(s) for details and contacts.' %
1320 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181321 warning_descriptions))
1322 return results
1323
1324
[email protected]fbcafe5a2012-08-08 15:31:221325def _CheckFilePermissions(input_api, output_api):
1326 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151327 if input_api.platform == 'win32':
1328 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291329 checkperms_tool = input_api.os_path.join(
1330 input_api.PresubmitLocalPath(),
1331 'tools', 'checkperms', 'checkperms.py')
1332 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471333 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391334 with input_api.CreateTemporaryFile() as file_list:
1335 for f in input_api.AffectedFiles():
1336 # checkperms.py file/directory arguments must be relative to the
1337 # repository.
1338 file_list.write(f.LocalPath() + '\n')
1339 file_list.close()
1340 args += ['--file-list', file_list.name]
1341 try:
1342 input_api.subprocess.check_output(args)
1343 return []
1344 except input_api.subprocess.CalledProcessError as error:
1345 return [output_api.PresubmitError(
1346 'checkperms.py failed:',
1347 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221348
1349
robertocn832f5992017-01-04 19:01:301350def _CheckTeamTags(input_api, output_api):
1351 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1352 checkteamtags_tool = input_api.os_path.join(
1353 input_api.PresubmitLocalPath(),
1354 'tools', 'checkteamtags', 'checkteamtags.py')
1355 args = [input_api.python_executable, checkteamtags_tool,
1356 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221357 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301358 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1359 'OWNERS']
1360 try:
1361 if files:
1362 input_api.subprocess.check_output(args + files)
1363 return []
1364 except input_api.subprocess.CalledProcessError as error:
1365 return [output_api.PresubmitError(
1366 'checkteamtags.py failed:',
1367 long_text=error.output)]
1368
1369
[email protected]c8278b32012-10-30 20:35:491370def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1371 """Makes sure we don't include ui/aura/window_property.h
1372 in header files.
1373 """
1374 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1375 errors = []
1376 for f in input_api.AffectedFiles():
1377 if not f.LocalPath().endswith('.h'):
1378 continue
1379 for line_num, line in f.ChangedContents():
1380 if pattern.match(line):
1381 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1382
1383 results = []
1384 if errors:
1385 results.append(output_api.PresubmitError(
1386 'Header files should not include ui/aura/window_property.h', errors))
1387 return results
1388
1389
[email protected]70ca77752012-11-20 03:45:031390def _CheckForVersionControlConflictsInFile(input_api, f):
1391 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1392 errors = []
1393 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161394 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231395 # First-level headers in markdown look a lot like version control
1396 # conflict markers. http://daringfireball.net/projects/markdown/basics
1397 continue
[email protected]70ca77752012-11-20 03:45:031398 if pattern.match(line):
1399 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1400 return errors
1401
1402
1403def _CheckForVersionControlConflicts(input_api, output_api):
1404 """Usually this is not intentional and will cause a compile failure."""
1405 errors = []
1406 for f in input_api.AffectedFiles():
1407 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1408
1409 results = []
1410 if errors:
1411 results.append(output_api.PresubmitError(
1412 'Version control conflict markers found, please resolve.', errors))
1413 return results
1414
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201415
estadee17314a02017-01-12 16:22:161416def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1417 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1418 errors = []
1419 for f in input_api.AffectedFiles():
1420 for line_num, line in f.ChangedContents():
1421 if pattern.search(line):
1422 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1423
1424 results = []
1425 if errors:
1426 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501427 'Found Google support URL addressed by answer number. Please replace '
1428 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161429 return results
1430
[email protected]70ca77752012-11-20 03:45:031431
[email protected]06e6d0ff2012-12-11 01:36:441432def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1433 def FilterFile(affected_file):
1434 """Filter function for use with input_api.AffectedSourceFiles,
1435 below. This filters out everything except non-test files from
1436 top-level directories that generally speaking should not hard-code
1437 service URLs (e.g. src/android_webview/, src/content/ and others).
1438 """
1439 return input_api.FilterSourceFile(
1440 affected_file,
Egor Paskoce145c42018-09-28 19:31:041441 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441442 black_list=(_EXCLUDED_PATHS +
1443 _TEST_CODE_EXCLUDED_PATHS +
1444 input_api.DEFAULT_BLACK_LIST))
1445
reillyi38965732015-11-16 18:27:331446 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1447 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461448 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1449 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441450 problems = [] # items are (filename, line_number, line)
1451 for f in input_api.AffectedSourceFiles(FilterFile):
1452 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461453 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441454 problems.append((f.LocalPath(), line_num, line))
1455
1456 if problems:
[email protected]f7051d52013-04-02 18:31:421457 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441458 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581459 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441460 [' %s:%d: %s' % (
1461 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031462 else:
1463 return []
[email protected]06e6d0ff2012-12-11 01:36:441464
1465
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491466# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271467def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1468 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311469 The native_client_sdk directory is excluded because it has auto-generated PNG
1470 files for documentation.
[email protected]d2530012013-01-25 16:39:271471 """
[email protected]d2530012013-01-25 16:39:271472 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491473 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041474 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311475 file_filter = lambda f: input_api.FilterSourceFile(
1476 f, white_list=white_list, black_list=black_list)
1477 for f in input_api.AffectedFiles(include_deletes=False,
1478 file_filter=file_filter):
1479 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271480
1481 results = []
1482 if errors:
1483 results.append(output_api.PresubmitError(
1484 'The name of PNG files should not have abbreviations. \n'
1485 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1486 'Contact [email protected] if you have questions.', errors))
1487 return results
1488
1489
Daniel Cheng4dcdb6b2017-04-13 08:30:171490def _ExtractAddRulesFromParsedDeps(parsed_deps):
1491 """Extract the rules that add dependencies from a parsed DEPS file.
1492
1493 Args:
1494 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1495 add_rules = set()
1496 add_rules.update([
1497 rule[1:] for rule in parsed_deps.get('include_rules', [])
1498 if rule.startswith('+') or rule.startswith('!')
1499 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501500 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171501 {}).iteritems():
1502 add_rules.update([
1503 rule[1:] for rule in rules
1504 if rule.startswith('+') or rule.startswith('!')
1505 ])
1506 return add_rules
1507
1508
1509def _ParseDeps(contents):
1510 """Simple helper for parsing DEPS files."""
1511 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171512 class _VarImpl:
1513
1514 def __init__(self, local_scope):
1515 self._local_scope = local_scope
1516
1517 def Lookup(self, var_name):
1518 """Implements the Var syntax."""
1519 try:
1520 return self._local_scope['vars'][var_name]
1521 except KeyError:
1522 raise Exception('Var is not defined: %s' % var_name)
1523
1524 local_scope = {}
1525 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171526 'Var': _VarImpl(local_scope).Lookup,
1527 }
1528 exec contents in global_scope, local_scope
1529 return local_scope
1530
1531
1532def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081533 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411534 a set of DEPS entries that we should look up.
1535
1536 For a directory (rather than a specific filename) we fake a path to
1537 a specific filename by adding /DEPS. This is chosen as a file that
1538 will seldom or never be subject to per-file include_rules.
1539 """
[email protected]2b438d62013-11-14 17:54:141540 # We ignore deps entries on auto-generated directories.
1541 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081542
Daniel Cheng4dcdb6b2017-04-13 08:30:171543 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1544 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1545
1546 added_deps = new_deps.difference(old_deps)
1547
[email protected]2b438d62013-11-14 17:54:141548 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171549 for added_dep in added_deps:
1550 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1551 continue
1552 # Assume that a rule that ends in .h is a rule for a specific file.
1553 if added_dep.endswith('.h'):
1554 results.add(added_dep)
1555 else:
1556 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081557 return results
1558
1559
[email protected]e871964c2013-05-13 14:14:551560def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1561 """When a dependency prefixed with + is added to a DEPS file, we
1562 want to make sure that the change is reviewed by an OWNER of the
1563 target file or directory, to avoid layering violations from being
1564 introduced. This check verifies that this happens.
1565 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171566 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241567
1568 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491569 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241570 for f in input_api.AffectedFiles(include_deletes=False,
1571 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551572 filename = input_api.os_path.basename(f.LocalPath())
1573 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171574 virtual_depended_on_files.update(_CalculateAddedDeps(
1575 input_api.os_path,
1576 '\n'.join(f.OldContents()),
1577 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551578
[email protected]e871964c2013-05-13 14:14:551579 if not virtual_depended_on_files:
1580 return []
1581
1582 if input_api.is_committing:
1583 if input_api.tbr:
1584 return [output_api.PresubmitNotifyResult(
1585 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271586 if input_api.dry_run:
1587 return [output_api.PresubmitNotifyResult(
1588 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551589 if not input_api.change.issue:
1590 return [output_api.PresubmitError(
1591 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401592 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551593 output = output_api.PresubmitError
1594 else:
1595 output = output_api.PresubmitNotifyResult
1596
1597 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501598 owner_email, reviewers = (
1599 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1600 input_api,
1601 owners_db.email_regexp,
1602 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551603
1604 owner_email = owner_email or input_api.change.author_email
1605
[email protected]de4f7d22013-05-23 14:27:461606 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511607 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461608 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551609 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1610 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411611
1612 # We strip the /DEPS part that was added by
1613 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1614 # directory.
1615 def StripDeps(path):
1616 start_deps = path.rfind('/DEPS')
1617 if start_deps != -1:
1618 return path[:start_deps]
1619 else:
1620 return path
1621 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551622 for path in missing_files]
1623
1624 if unapproved_dependencies:
1625 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151626 output('You need LGTM from owners of depends-on paths in DEPS that were '
1627 'modified in this CL:\n %s' %
1628 '\n '.join(sorted(unapproved_dependencies)))]
1629 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1630 output_list.append(output(
1631 'Suggested missing target path OWNERS:\n %s' %
1632 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551633 return output_list
1634
1635 return []
1636
1637
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491638# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401639def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491640 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401641 black_list = (_EXCLUDED_PATHS +
1642 _TEST_CODE_EXCLUDED_PATHS +
1643 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041644 (r"^base[\\/]logging\.h$",
1645 r"^base[\\/]logging\.cc$",
1646 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1647 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1648 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121649 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041650 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1651 r"^chrome[\\/]chrome_cleaner[\\/].*",
1652 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031653 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041654 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1655 r"^chromecast[\\/]",
1656 r"^cloud_print[\\/]",
1657 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481658 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041659 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311660 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041661 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461662 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041663 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461664 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041665 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251666 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041667 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1668 r"^courgette[\\/]courgette_tool\.cc$",
1669 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271670 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331671 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041672 r"^ipc[\\/]ipc_logging\.cc$",
1673 r"^native_client_sdk[\\/]",
1674 r"^remoting[\\/]base[\\/]logging\.h$",
1675 r"^remoting[\\/]host[\\/].*",
1676 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331677 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1678 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041679 r"^tools[\\/]",
1680 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1681 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331682 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401683 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491684 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401685
thomasanderson625d3932017-03-29 07:16:581686 log_info = set([])
1687 printf = set([])
[email protected]85218562013-11-22 07:41:401688
1689 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581690 for _, line in f.ChangedContents():
1691 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1692 log_info.add(f.LocalPath())
1693 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1694 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371695
thomasanderson625d3932017-03-29 07:16:581696 if input_api.re.search(r"\bprintf\(", line):
1697 printf.add(f.LocalPath())
1698 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1699 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401700
1701 if log_info:
1702 return [output_api.PresubmitError(
1703 'These files spam the console log with LOG(INFO):',
1704 items=log_info)]
1705 if printf:
1706 return [output_api.PresubmitError(
1707 'These files spam the console log with printf/fprintf:',
1708 items=printf)]
1709 return []
1710
1711
[email protected]49aa76a2013-12-04 06:59:161712def _CheckForAnonymousVariables(input_api, output_api):
1713 """These types are all expected to hold locks while in scope and
1714 so should never be anonymous (which causes them to be immediately
1715 destroyed)."""
1716 they_who_must_be_named = [
1717 'base::AutoLock',
1718 'base::AutoReset',
1719 'base::AutoUnlock',
1720 'SkAutoAlphaRestore',
1721 'SkAutoBitmapShaderInstall',
1722 'SkAutoBlitterChoose',
1723 'SkAutoBounderCommit',
1724 'SkAutoCallProc',
1725 'SkAutoCanvasRestore',
1726 'SkAutoCommentBlock',
1727 'SkAutoDescriptor',
1728 'SkAutoDisableDirectionCheck',
1729 'SkAutoDisableOvalCheck',
1730 'SkAutoFree',
1731 'SkAutoGlyphCache',
1732 'SkAutoHDC',
1733 'SkAutoLockColors',
1734 'SkAutoLockPixels',
1735 'SkAutoMalloc',
1736 'SkAutoMaskFreeImage',
1737 'SkAutoMutexAcquire',
1738 'SkAutoPathBoundsUpdate',
1739 'SkAutoPDFRelease',
1740 'SkAutoRasterClipValidate',
1741 'SkAutoRef',
1742 'SkAutoTime',
1743 'SkAutoTrace',
1744 'SkAutoUnref',
1745 ]
1746 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1747 # bad: base::AutoLock(lock.get());
1748 # not bad: base::AutoLock lock(lock.get());
1749 bad_pattern = input_api.re.compile(anonymous)
1750 # good: new base::AutoLock(lock.get())
1751 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1752 errors = []
1753
1754 for f in input_api.AffectedFiles():
1755 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1756 continue
1757 for linenum, line in f.ChangedContents():
1758 if bad_pattern.search(line) and not good_pattern.search(line):
1759 errors.append('%s:%d' % (f.LocalPath(), linenum))
1760
1761 if errors:
1762 return [output_api.PresubmitError(
1763 'These lines create anonymous variables that need to be named:',
1764 items=errors)]
1765 return []
1766
1767
Peter Kasting4844e46e2018-02-23 07:27:101768def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531769 # Returns whether |template_str| is of the form <T, U...> for some types T
1770 # and U. Assumes that |template_str| is already in the form <...>.
1771 def HasMoreThanOneArg(template_str):
1772 # Level of <...> nesting.
1773 nesting = 0
1774 for c in template_str:
1775 if c == '<':
1776 nesting += 1
1777 elif c == '>':
1778 nesting -= 1
1779 elif c == ',' and nesting == 1:
1780 return True
1781 return False
1782
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491783 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101784 sources = lambda affected_file: input_api.FilterSourceFile(
1785 affected_file,
1786 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1787 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491788 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551789
1790 # Pattern to capture a single "<...>" block of template arguments. It can
1791 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1792 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1793 # latter would likely require counting that < and > match, which is not
1794 # expressible in regular languages. Should the need arise, one can introduce
1795 # limited counting (matching up to a total number of nesting depth), which
1796 # should cover all practical cases for already a low nesting limit.
1797 template_arg_pattern = (
1798 r'<[^>]*' # Opening block of <.
1799 r'>([^<]*>)?') # Closing block of >.
1800 # Prefix expressing that whatever follows is not already inside a <...>
1801 # block.
1802 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101803 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551804 not_inside_template_arg_pattern
1805 + r'\bstd::unique_ptr'
1806 + template_arg_pattern
1807 + r'\(\)')
1808
1809 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1810 template_arg_no_array_pattern = (
1811 r'<[^>]*[^]]' # Opening block of <.
1812 r'>([^(<]*[^]]>)?') # Closing block of >.
1813 # Prefix saying that what follows is the start of an expression.
1814 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1815 # Suffix saying that what follows are call parentheses with a non-empty list
1816 # of arguments.
1817 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531818 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551819 return_construct_pattern = input_api.re.compile(
1820 start_of_expr_pattern
1821 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531822 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551823 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531824 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551825 + nonempty_arg_list_pattern)
1826
Vaclav Brozek851d9602018-04-04 16:13:051827 problems_constructor = []
1828 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101829 for f in input_api.AffectedSourceFiles(sources):
1830 for line_number, line in f.ChangedContents():
1831 # Disallow:
1832 # return std::unique_ptr<T>(foo);
1833 # bar = std::unique_ptr<T>(foo);
1834 # But allow:
1835 # return std::unique_ptr<T[]>(foo);
1836 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531837 # And also allow cases when the second template argument is present. Those
1838 # cases cannot be handled by std::make_unique:
1839 # return std::unique_ptr<T, U>(foo);
1840 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051841 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531842 return_construct_result = return_construct_pattern.search(line)
1843 if return_construct_result and not HasMoreThanOneArg(
1844 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051845 problems_constructor.append(
1846 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101847 # Disallow:
1848 # std::unique_ptr<T>()
1849 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051850 problems_nullptr.append(
1851 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1852
1853 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161854 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051855 errors.append(output_api.PresubmitError(
1856 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161857 problems_nullptr))
1858 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051859 errors.append(output_api.PresubmitError(
1860 'The following files use explicit std::unique_ptr constructor.'
1861 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161862 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101863 return errors
1864
1865
[email protected]999261d2014-03-03 20:08:081866def _CheckUserActionUpdate(input_api, output_api):
1867 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521868 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081869 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521870 # If actions.xml is already included in the changelist, the PRESUBMIT
1871 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081872 return []
1873
[email protected]999261d2014-03-03 20:08:081874 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1875 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521876 current_actions = None
[email protected]999261d2014-03-03 20:08:081877 for f in input_api.AffectedFiles(file_filter=file_filter):
1878 for line_num, line in f.ChangedContents():
1879 match = input_api.re.search(action_re, line)
1880 if match:
[email protected]2f92dec2014-03-07 19:21:521881 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1882 # loaded only once.
1883 if not current_actions:
1884 with open('tools/metrics/actions/actions.xml') as actions_f:
1885 current_actions = actions_f.read()
1886 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081887 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521888 action = 'name="{0}"'.format(action_name)
1889 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081890 return [output_api.PresubmitPromptWarning(
1891 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521892 'tools/metrics/actions/actions.xml. Please run '
1893 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081894 % (f.LocalPath(), line_num, action_name))]
1895 return []
1896
1897
Daniel Cheng13ca61a882017-08-25 15:11:251898def _ImportJSONCommentEater(input_api):
1899 import sys
1900 sys.path = sys.path + [input_api.os_path.join(
1901 input_api.PresubmitLocalPath(),
1902 'tools', 'json_comment_eater')]
1903 import json_comment_eater
1904 return json_comment_eater
1905
1906
[email protected]99171a92014-06-03 08:44:471907def _GetJSONParseError(input_api, filename, eat_comments=True):
1908 try:
1909 contents = input_api.ReadFile(filename)
1910 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251911 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131912 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471913
1914 input_api.json.loads(contents)
1915 except ValueError as e:
1916 return e
1917 return None
1918
1919
1920def _GetIDLParseError(input_api, filename):
1921 try:
1922 contents = input_api.ReadFile(filename)
1923 idl_schema = input_api.os_path.join(
1924 input_api.PresubmitLocalPath(),
1925 'tools', 'json_schema_compiler', 'idl_schema.py')
1926 process = input_api.subprocess.Popen(
1927 [input_api.python_executable, idl_schema],
1928 stdin=input_api.subprocess.PIPE,
1929 stdout=input_api.subprocess.PIPE,
1930 stderr=input_api.subprocess.PIPE,
1931 universal_newlines=True)
1932 (_, error) = process.communicate(input=contents)
1933 return error or None
1934 except ValueError as e:
1935 return e
1936
1937
1938def _CheckParseErrors(input_api, output_api):
1939 """Check that IDL and JSON files do not contain syntax errors."""
1940 actions = {
1941 '.idl': _GetIDLParseError,
1942 '.json': _GetJSONParseError,
1943 }
[email protected]99171a92014-06-03 08:44:471944 # Most JSON files are preprocessed and support comments, but these do not.
1945 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041946 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471947 ]
1948 # Only run IDL checker on files in these directories.
1949 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041950 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1951 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471952 ]
1953
1954 def get_action(affected_file):
1955 filename = affected_file.LocalPath()
1956 return actions.get(input_api.os_path.splitext(filename)[1])
1957
[email protected]99171a92014-06-03 08:44:471958 def FilterFile(affected_file):
1959 action = get_action(affected_file)
1960 if not action:
1961 return False
1962 path = affected_file.LocalPath()
1963
Sean Kau46e29bc2017-08-28 16:31:161964 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471965 return False
1966
1967 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161968 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471969 return False
1970 return True
1971
1972 results = []
1973 for affected_file in input_api.AffectedFiles(
1974 file_filter=FilterFile, include_deletes=False):
1975 action = get_action(affected_file)
1976 kwargs = {}
1977 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161978 _MatchesFile(input_api, json_no_comments_patterns,
1979 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471980 kwargs['eat_comments'] = False
1981 parse_error = action(input_api,
1982 affected_file.AbsoluteLocalPath(),
1983 **kwargs)
1984 if parse_error:
1985 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1986 (affected_file.LocalPath(), parse_error)))
1987 return results
1988
1989
[email protected]760deea2013-12-10 19:33:491990def _CheckJavaStyle(input_api, output_api):
1991 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471992 import sys
[email protected]760deea2013-12-10 19:33:491993 original_sys_path = sys.path
1994 try:
1995 sys.path = sys.path + [input_api.os_path.join(
1996 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1997 import checkstyle
1998 finally:
1999 # Restore sys.path to what it was before.
2000 sys.path = original_sys_path
2001
2002 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092003 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512004 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492005
2006
Sean Kau46e29bc2017-08-28 16:31:162007def _MatchesFile(input_api, patterns, path):
2008 for pattern in patterns:
2009 if input_api.re.search(pattern, path):
2010 return True
2011 return False
2012
2013
Daniel Cheng7052cdf2017-11-21 19:23:292014def _GetOwnersFilesToCheckForIpcOwners(input_api):
2015 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172016
Daniel Cheng7052cdf2017-11-21 19:23:292017 Returns:
2018 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2019 contain to cover IPC-related files with noparent reviewer rules.
2020 """
2021 # Whether or not a file affects IPC is (mostly) determined by a simple list
2022 # of filename patterns.
dchenge07de812016-06-20 19:27:172023 file_patterns = [
palmerb19a0932017-01-24 04:00:312024 # Legacy IPC:
dchenge07de812016-06-20 19:27:172025 '*_messages.cc',
2026 '*_messages*.h',
2027 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312028 # Mojo IPC:
dchenge07de812016-06-20 19:27:172029 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472030 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172031 '*_struct_traits*.*',
2032 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312033 '*.typemap',
2034 # Android native IPC:
2035 '*.aidl',
2036 # Blink uses a different file naming convention:
2037 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472038 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172039 '*StructTraits*.*',
2040 '*TypeConverter*.*',
2041 ]
2042
scottmg7a6ed5ba2016-11-04 18:22:042043 # These third_party directories do not contain IPCs, but contain files
2044 # matching the above patterns, which trigger false positives.
2045 exclude_paths = [
2046 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232047 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062048 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292049 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042050 ]
2051
dchenge07de812016-06-20 19:27:172052 # Dictionary mapping an OWNERS file path to Patterns.
2053 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2054 # rules ) to a PatternEntry.
2055 # PatternEntry is a dictionary with two keys:
2056 # - 'files': the files that are matched by this pattern
2057 # - 'rules': the per-file rules needed for this pattern
2058 # For example, if we expect OWNERS file to contain rules for *.mojom and
2059 # *_struct_traits*.*, Patterns might look like this:
2060 # {
2061 # '*.mojom': {
2062 # 'files': ...,
2063 # 'rules': [
2064 # 'per-file *.mojom=set noparent',
2065 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2066 # ],
2067 # },
2068 # '*_struct_traits*.*': {
2069 # 'files': ...,
2070 # 'rules': [
2071 # 'per-file *_struct_traits*.*=set noparent',
2072 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2073 # ],
2074 # },
2075 # }
2076 to_check = {}
2077
Daniel Cheng13ca61a882017-08-25 15:11:252078 def AddPatternToCheck(input_file, pattern):
2079 owners_file = input_api.os_path.join(
2080 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2081 if owners_file not in to_check:
2082 to_check[owners_file] = {}
2083 if pattern not in to_check[owners_file]:
2084 to_check[owners_file][pattern] = {
2085 'files': [],
2086 'rules': [
2087 'per-file %s=set noparent' % pattern,
2088 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2089 ]
2090 }
Vaclav Brozekd5de76a2018-03-17 07:57:502091 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252092
dchenge07de812016-06-20 19:27:172093 # Iterate through the affected files to see what we actually need to check
2094 # for. We should only nag patch authors about per-file rules if a file in that
2095 # directory would match that pattern. If a directory only contains *.mojom
2096 # files and no *_messages*.h files, we should only nag about rules for
2097 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252098 for f in input_api.AffectedFiles(include_deletes=False):
2099 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362100 # affected files for .json, .cc, and .h files which look like they contain
2101 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162102 if (f.LocalPath().endswith('.json') and
2103 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2104 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252105 json_comment_eater = _ImportJSONCommentEater(input_api)
2106 mostly_json_lines = '\n'.join(f.NewContents())
2107 # Comments aren't allowed in strict JSON, so filter them out.
2108 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432109 try:
2110 json_content = input_api.json.loads(json_lines)
2111 except:
2112 # There's another PRESUBMIT check that already verifies that JSON files
2113 # are not invalid, so no need to emit another warning here.
2114 continue
Daniel Cheng13ca61a882017-08-25 15:11:252115 if 'interface_provider_specs' in json_content:
2116 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362117 else:
2118 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2119 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2120 if (manifest_pattern.search(f.LocalPath()) and not
2121 test_manifest_pattern.search(f.LocalPath())):
2122 # We expect all actual service manifest files to contain at least one
2123 # qualified reference to service_manager::Manifest.
2124 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2125 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172126 for pattern in file_patterns:
2127 if input_api.fnmatch.fnmatch(
2128 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042129 skip = False
2130 for exclude in exclude_paths:
2131 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2132 skip = True
2133 break
2134 if skip:
2135 continue
Daniel Cheng13ca61a882017-08-25 15:11:252136 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172137 break
2138
Daniel Cheng7052cdf2017-11-21 19:23:292139 return to_check
2140
2141
2142def _CheckIpcOwners(input_api, output_api):
2143 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2144 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2145
2146 if to_check:
2147 # If there are any OWNERS files to check, there are IPC-related changes in
2148 # this CL. Auto-CC the review list.
2149 output_api.AppendCC('[email protected]')
2150
2151 # Go through the OWNERS files to check, filtering out rules that are already
2152 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172153 for owners_file, patterns in to_check.iteritems():
2154 try:
2155 with file(owners_file) as f:
2156 lines = set(f.read().splitlines())
2157 for entry in patterns.itervalues():
2158 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2159 ]
2160 except IOError:
2161 # No OWNERS file, so all the rules are definitely missing.
2162 continue
2163
2164 # All the remaining lines weren't found in OWNERS files, so emit an error.
2165 errors = []
2166 for owners_file, patterns in to_check.iteritems():
2167 missing_lines = []
2168 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502169 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172170 missing_lines.extend(entry['rules'])
2171 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2172 if missing_lines:
2173 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052174 'Because of the presence of files:\n%s\n\n'
2175 '%s needs the following %d lines added:\n\n%s' %
2176 ('\n'.join(files), owners_file, len(missing_lines),
2177 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172178
2179 results = []
2180 if errors:
vabrf5ce3bf92016-07-11 14:52:412181 if input_api.is_committing:
2182 output = output_api.PresubmitError
2183 else:
2184 output = output_api.PresubmitPromptWarning
2185 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592186 'Found OWNERS files that need to be updated for IPC security ' +
2187 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172188 long_text='\n\n'.join(errors)))
2189
2190 return results
2191
2192
jbriance9e12f162016-11-25 07:57:502193def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312194 """Checks that added or removed lines in non third party affected
2195 header files do not lead to new useless class or struct forward
2196 declaration.
jbriance9e12f162016-11-25 07:57:502197 """
2198 results = []
2199 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2200 input_api.re.MULTILINE)
2201 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2202 input_api.re.MULTILINE)
2203 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312204 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192205 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492206 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312207 continue
2208
jbriance9e12f162016-11-25 07:57:502209 if not f.LocalPath().endswith('.h'):
2210 continue
2211
2212 contents = input_api.ReadFile(f)
2213 fwd_decls = input_api.re.findall(class_pattern, contents)
2214 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2215
2216 useless_fwd_decls = []
2217 for decl in fwd_decls:
2218 count = sum(1 for _ in input_api.re.finditer(
2219 r'\b%s\b' % input_api.re.escape(decl), contents))
2220 if count == 1:
2221 useless_fwd_decls.append(decl)
2222
2223 if not useless_fwd_decls:
2224 continue
2225
2226 for line in f.GenerateScmDiff().splitlines():
2227 if (line.startswith('-') and not line.startswith('--') or
2228 line.startswith('+') and not line.startswith('++')):
2229 for decl in useless_fwd_decls:
2230 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2231 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242232 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502233 (f.LocalPath(), decl)))
2234 useless_fwd_decls.remove(decl)
2235
2236 return results
2237
2238
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492239# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292240def _CheckAndroidToastUsage(input_api, output_api):
2241 """Checks that code uses org.chromium.ui.widget.Toast instead of
2242 android.widget.Toast (Chromium Toast doesn't force hardware
2243 acceleration on low-end devices, saving memory).
2244 """
2245 toast_import_pattern = input_api.re.compile(
2246 r'^import android\.widget\.Toast;$')
2247
2248 errors = []
2249
2250 sources = lambda affected_file: input_api.FilterSourceFile(
2251 affected_file,
2252 black_list=(_EXCLUDED_PATHS +
2253 _TEST_CODE_EXCLUDED_PATHS +
2254 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042255 (r'^chromecast[\\/].*',
2256 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492257 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292258
2259 for f in input_api.AffectedSourceFiles(sources):
2260 for line_num, line in f.ChangedContents():
2261 if toast_import_pattern.search(line):
2262 errors.append("%s:%d" % (f.LocalPath(), line_num))
2263
2264 results = []
2265
2266 if errors:
2267 results.append(output_api.PresubmitError(
2268 'android.widget.Toast usage is detected. Android toasts use hardware'
2269 ' acceleration, and can be\ncostly on low-end devices. Please use'
2270 ' org.chromium.ui.widget.Toast instead.\n'
2271 'Contact [email protected] if you have any questions.',
2272 errors))
2273
2274 return results
2275
2276
dgnaa68d5e2015-06-10 10:08:222277def _CheckAndroidCrLogUsage(input_api, output_api):
2278 """Checks that new logs using org.chromium.base.Log:
2279 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512280 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222281 """
pkotwicza1dd0b002016-05-16 14:41:042282
torne89540622017-03-24 19:41:302283 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042284 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302285 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042286 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302287 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042288 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2289 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092290 # The customtabs_benchmark is a small app that does not depend on Chromium
2291 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042292 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042293 ]
2294
dgnaa68d5e2015-06-10 10:08:222295 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122296 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2297 class_in_base_pattern = input_api.re.compile(
2298 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2299 has_some_log_import_pattern = input_api.re.compile(
2300 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222301 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122302 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222303 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512304 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222305 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222306
Vincent Scheib16d7b272015-09-15 18:09:072307 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222308 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492309 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042310 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122311
dgnaa68d5e2015-06-10 10:08:222312 tag_decl_errors = []
2313 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122314 tag_errors = []
dgn38736db2015-09-18 19:20:512315 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122316 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222317
2318 for f in input_api.AffectedSourceFiles(sources):
2319 file_content = input_api.ReadFile(f)
2320 has_modified_logs = False
2321
2322 # Per line checks
dgn87d9fb62015-06-12 09:15:122323 if (cr_log_import_pattern.search(file_content) or
2324 (class_in_base_pattern.search(file_content) and
2325 not has_some_log_import_pattern.search(file_content))):
2326 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222327 for line_num, line in f.ChangedContents():
2328
2329 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122330 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222331 if match:
2332 has_modified_logs = True
2333
2334 # Make sure it uses "TAG"
2335 if not match.group('tag') == 'TAG':
2336 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122337 else:
2338 # Report non cr Log function calls in changed lines
2339 for line_num, line in f.ChangedContents():
2340 if log_call_pattern.search(line):
2341 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222342
2343 # Per file checks
2344 if has_modified_logs:
2345 # Make sure the tag is using the "cr" prefix and is not too long
2346 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512347 tag_name = match.group('name') if match else None
2348 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222349 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512350 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222351 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512352 elif '.' in tag_name:
2353 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222354
2355 results = []
2356 if tag_decl_errors:
2357 results.append(output_api.PresubmitPromptWarning(
2358 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512359 '"private static final String TAG = "<package tag>".\n'
2360 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222361 tag_decl_errors))
2362
2363 if tag_length_errors:
2364 results.append(output_api.PresubmitError(
2365 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512366 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222367 tag_length_errors))
2368
2369 if tag_errors:
2370 results.append(output_api.PresubmitPromptWarning(
2371 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2372 tag_errors))
2373
dgn87d9fb62015-06-12 09:15:122374 if util_log_errors:
dgn4401aa52015-04-29 16:26:172375 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122376 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2377 util_log_errors))
2378
dgn38736db2015-09-18 19:20:512379 if tag_with_dot_errors:
2380 results.append(output_api.PresubmitPromptWarning(
2381 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2382 tag_with_dot_errors))
2383
dgn4401aa52015-04-29 16:26:172384 return results
2385
2386
Yoland Yanb92fa522017-08-28 17:37:062387def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2388 """Checks that junit.framework.* is no longer used."""
2389 deprecated_junit_framework_pattern = input_api.re.compile(
2390 r'^import junit\.framework\..*;',
2391 input_api.re.MULTILINE)
2392 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492393 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062394 errors = []
2395 for f in input_api.AffectedFiles(sources):
2396 for line_num, line in f.ChangedContents():
2397 if deprecated_junit_framework_pattern.search(line):
2398 errors.append("%s:%d" % (f.LocalPath(), line_num))
2399
2400 results = []
2401 if errors:
2402 results.append(output_api.PresubmitError(
2403 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2404 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2405 ' if you have any question.', errors))
2406 return results
2407
2408
2409def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2410 """Checks that if new Java test classes have inheritance.
2411 Either the new test class is JUnit3 test or it is a JUnit4 test class
2412 with a base class, either case is undesirable.
2413 """
2414 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2415
2416 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492417 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062418 errors = []
2419 for f in input_api.AffectedFiles(sources):
2420 if not f.OldContents():
2421 class_declaration_start_flag = False
2422 for line_num, line in f.ChangedContents():
2423 if class_declaration_pattern.search(line):
2424 class_declaration_start_flag = True
2425 if class_declaration_start_flag and ' extends ' in line:
2426 errors.append('%s:%d' % (f.LocalPath(), line_num))
2427 if '{' in line:
2428 class_declaration_start_flag = False
2429
2430 results = []
2431 if errors:
2432 results.append(output_api.PresubmitPromptWarning(
2433 'The newly created files include Test classes that inherits from base'
2434 ' class. Please do not use inheritance in JUnit4 tests or add new'
2435 ' JUnit3 tests. Contact [email protected] if you have any'
2436 ' questions.', errors))
2437 return results
2438
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202439
yolandyan45001472016-12-21 21:12:422440def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2441 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2442 deprecated_annotation_import_pattern = input_api.re.compile(
2443 r'^import android\.test\.suitebuilder\.annotation\..*;',
2444 input_api.re.MULTILINE)
2445 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492446 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422447 errors = []
2448 for f in input_api.AffectedFiles(sources):
2449 for line_num, line in f.ChangedContents():
2450 if deprecated_annotation_import_pattern.search(line):
2451 errors.append("%s:%d" % (f.LocalPath(), line_num))
2452
2453 results = []
2454 if errors:
2455 results.append(output_api.PresubmitError(
2456 'Annotations in android.test.suitebuilder.annotation have been'
2457 ' deprecated since API level 24. Please use android.support.test.filters'
2458 ' from //third_party/android_support_test_runner:runner_java instead.'
2459 ' Contact [email protected] if you have any questions.', errors))
2460 return results
2461
2462
agrieve7b6479d82015-10-07 14:24:222463def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2464 """Checks if MDPI assets are placed in a correct directory."""
2465 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2466 ('/res/drawable/' in f.LocalPath() or
2467 '/res/drawable-ldrtl/' in f.LocalPath()))
2468 errors = []
2469 for f in input_api.AffectedFiles(include_deletes=False,
2470 file_filter=file_filter):
2471 errors.append(' %s' % f.LocalPath())
2472
2473 results = []
2474 if errors:
2475 results.append(output_api.PresubmitError(
2476 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2477 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2478 '/res/drawable-ldrtl/.\n'
2479 'Contact [email protected] if you have questions.', errors))
2480 return results
2481
2482
Nate Fischer535972b2017-09-16 01:06:182483def _CheckAndroidWebkitImports(input_api, output_api):
2484 """Checks that code uses org.chromium.base.Callback instead of
2485 android.widget.ValueCallback except in the WebView glue layer.
2486 """
2487 valuecallback_import_pattern = input_api.re.compile(
2488 r'^import android\.webkit\.ValueCallback;$')
2489
2490 errors = []
2491
2492 sources = lambda affected_file: input_api.FilterSourceFile(
2493 affected_file,
2494 black_list=(_EXCLUDED_PATHS +
2495 _TEST_CODE_EXCLUDED_PATHS +
2496 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042497 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492498 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182499
2500 for f in input_api.AffectedSourceFiles(sources):
2501 for line_num, line in f.ChangedContents():
2502 if valuecallback_import_pattern.search(line):
2503 errors.append("%s:%d" % (f.LocalPath(), line_num))
2504
2505 results = []
2506
2507 if errors:
2508 results.append(output_api.PresubmitError(
2509 'android.webkit.ValueCallback usage is detected outside of the glue'
2510 ' layer. To stay compatible with the support library, android.webkit.*'
2511 ' classes should only be used inside the glue layer and'
2512 ' org.chromium.base.Callback should be used instead.',
2513 errors))
2514
2515 return results
2516
2517
Becky Zhou7c69b50992018-12-10 19:37:572518def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2519 """Checks Android XML styles """
2520 import sys
2521 original_sys_path = sys.path
2522 try:
2523 sys.path = sys.path + [input_api.os_path.join(
2524 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2525 import checkxmlstyle
2526 finally:
2527 # Restore sys.path to what it was before.
2528 sys.path = original_sys_path
2529
2530 if is_check_on_upload:
2531 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2532 else:
2533 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2534
2535
agrievef32bcc72016-04-04 14:57:402536class PydepsChecker(object):
2537 def __init__(self, input_api, pydeps_files):
2538 self._file_cache = {}
2539 self._input_api = input_api
2540 self._pydeps_files = pydeps_files
2541
2542 def _LoadFile(self, path):
2543 """Returns the list of paths within a .pydeps file relative to //."""
2544 if path not in self._file_cache:
2545 with open(path) as f:
2546 self._file_cache[path] = f.read()
2547 return self._file_cache[path]
2548
2549 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2550 """Returns an interable of paths within the .pydep, relativized to //."""
2551 os_path = self._input_api.os_path
2552 pydeps_dir = os_path.dirname(pydeps_path)
2553 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2554 if not l.startswith('*'))
2555 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2556
2557 def _CreateFilesToPydepsMap(self):
2558 """Returns a map of local_path -> list_of_pydeps."""
2559 ret = {}
2560 for pydep_local_path in self._pydeps_files:
2561 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2562 ret.setdefault(path, []).append(pydep_local_path)
2563 return ret
2564
2565 def ComputeAffectedPydeps(self):
2566 """Returns an iterable of .pydeps files that might need regenerating."""
2567 affected_pydeps = set()
2568 file_to_pydeps_map = None
2569 for f in self._input_api.AffectedFiles(include_deletes=True):
2570 local_path = f.LocalPath()
2571 if local_path == 'DEPS':
2572 return self._pydeps_files
2573 elif local_path.endswith('.pydeps'):
2574 if local_path in self._pydeps_files:
2575 affected_pydeps.add(local_path)
2576 elif local_path.endswith('.py'):
2577 if file_to_pydeps_map is None:
2578 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2579 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2580 return affected_pydeps
2581
2582 def DetermineIfStale(self, pydeps_path):
2583 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412584 import difflib
John Budorick47ca3fe2018-02-10 00:53:102585 import os
2586
agrievef32bcc72016-04-04 14:57:402587 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2588 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102589 env = dict(os.environ)
2590 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402591 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102592 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412593 old_contents = old_pydeps_data[2:]
2594 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402595 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412596 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402597
2598
2599def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2600 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402601 # This check is for Python dependency lists (.pydeps files), and involves
2602 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2603 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282604 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002605 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022606 # TODO(agrieve): Update when there's a better way to detect
2607 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402608 is_android = input_api.os_path.exists('third_party/android_tools')
2609 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2610 results = []
2611 # First, check for new / deleted .pydeps.
2612 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032613 # Check whether we are running the presubmit check for a file in src.
2614 # f.LocalPath is relative to repo (src, or internal repo).
2615 # os_path.exists is relative to src repo.
2616 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2617 # to src and we can conclude that the pydeps is in src.
2618 if input_api.os_path.exists(f.LocalPath()):
2619 if f.LocalPath().endswith('.pydeps'):
2620 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2621 results.append(output_api.PresubmitError(
2622 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2623 'remove %s' % f.LocalPath()))
2624 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2625 results.append(output_api.PresubmitError(
2626 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2627 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402628
2629 if results:
2630 return results
2631
2632 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2633
2634 for pydep_path in checker.ComputeAffectedPydeps():
2635 try:
phajdan.jr0d9878552016-11-04 10:49:412636 result = checker.DetermineIfStale(pydep_path)
2637 if result:
2638 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402639 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412640 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2641 'To regenerate, run:\n\n %s' %
2642 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402643 except input_api.subprocess.CalledProcessError as error:
2644 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2645 long_text=error.output)]
2646
2647 return results
2648
2649
glidere61efad2015-02-18 17:39:432650def _CheckSingletonInHeaders(input_api, output_api):
2651 """Checks to make sure no header files have |Singleton<|."""
2652 def FileFilter(affected_file):
2653 # It's ok for base/memory/singleton.h to have |Singleton<|.
2654 black_list = (_EXCLUDED_PATHS +
2655 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042656 (r"^base[\\/]memory[\\/]singleton\.h$",
2657 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472658 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432659 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2660
sergeyu34d21222015-09-16 00:11:442661 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432662 files = []
2663 for f in input_api.AffectedSourceFiles(FileFilter):
2664 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2665 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2666 contents = input_api.ReadFile(f)
2667 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242668 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432669 pattern.search(line)):
2670 files.append(f)
2671 break
2672
2673 if files:
yolandyandaabc6d2016-04-18 18:29:392674 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442675 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432676 'Please move them to an appropriate source file so that the ' +
2677 'template gets instantiated in a single compilation unit.',
2678 files) ]
2679 return []
2680
2681
[email protected]fd20b902014-05-09 02:14:532682_DEPRECATED_CSS = [
2683 # Values
2684 ( "-webkit-box", "flex" ),
2685 ( "-webkit-inline-box", "inline-flex" ),
2686 ( "-webkit-flex", "flex" ),
2687 ( "-webkit-inline-flex", "inline-flex" ),
2688 ( "-webkit-min-content", "min-content" ),
2689 ( "-webkit-max-content", "max-content" ),
2690
2691 # Properties
2692 ( "-webkit-background-clip", "background-clip" ),
2693 ( "-webkit-background-origin", "background-origin" ),
2694 ( "-webkit-background-size", "background-size" ),
2695 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442696 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532697
2698 # Functions
2699 ( "-webkit-gradient", "gradient" ),
2700 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2701 ( "-webkit-linear-gradient", "linear-gradient" ),
2702 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2703 ( "-webkit-radial-gradient", "radial-gradient" ),
2704 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2705]
2706
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202707
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492708# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242709def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532710 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252711 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342712 documentation and iOS CSS for dom distiller
2713 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252714 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532715 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492716 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252717 black_list = (_EXCLUDED_PATHS +
2718 _TEST_CODE_EXCLUDED_PATHS +
2719 input_api.DEFAULT_BLACK_LIST +
2720 (r"^chrome/common/extensions/docs",
2721 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342722 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442723 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252724 r"^native_client_sdk"))
2725 file_filter = lambda f: input_api.FilterSourceFile(
2726 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532727 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2728 for line_num, line in fpath.ChangedContents():
2729 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022730 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532731 results.append(output_api.PresubmitError(
2732 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2733 (fpath.LocalPath(), line_num, deprecated_value, value)))
2734 return results
2735
mohan.reddyf21db962014-10-16 12:26:472736
dbeam070cfe62014-10-22 06:44:022737_DEPRECATED_JS = [
2738 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2739 ( "__defineGetter__", "Object.defineProperty" ),
2740 ( "__defineSetter__", "Object.defineProperty" ),
2741]
2742
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202743
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492744# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242745def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022746 """Make sure that we don't use deprecated JS in Chrome code."""
2747 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492748 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022749 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2750 input_api.DEFAULT_BLACK_LIST)
2751 file_filter = lambda f: input_api.FilterSourceFile(
2752 f, white_list=file_inclusion_pattern, black_list=black_list)
2753 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2754 for lnum, line in fpath.ChangedContents():
2755 for (deprecated, replacement) in _DEPRECATED_JS:
2756 if deprecated in line:
2757 results.append(output_api.PresubmitError(
2758 "%s:%d: Use of deprecated JS %s, use %s instead" %
2759 (fpath.LocalPath(), lnum, deprecated, replacement)))
2760 return results
2761
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202762
rlanday6802cf632017-05-30 17:48:362763def _CheckForRelativeIncludes(input_api, output_api):
2764 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2765 import sys
2766 original_sys_path = sys.path
2767 try:
2768 sys.path = sys.path + [input_api.os_path.join(
2769 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2770 from cpp_checker import CppChecker
2771 finally:
2772 # Restore sys.path to what it was before.
2773 sys.path = original_sys_path
2774
2775 bad_files = {}
2776 for f in input_api.AffectedFiles(include_deletes=False):
2777 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492778 not f.LocalPath().startswith('third_party/blink') and
2779 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362780 continue
2781
2782 if not CppChecker.IsCppFile(f.LocalPath()):
2783 continue
2784
Vaclav Brozekd5de76a2018-03-17 07:57:502785 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362786 if "#include" in line and "../" in line]
2787 if not relative_includes:
2788 continue
2789 bad_files[f.LocalPath()] = relative_includes
2790
2791 if not bad_files:
2792 return []
2793
2794 error_descriptions = []
2795 for file_path, bad_lines in bad_files.iteritems():
2796 error_description = file_path
2797 for line in bad_lines:
2798 error_description += '\n ' + line
2799 error_descriptions.append(error_description)
2800
2801 results = []
2802 results.append(output_api.PresubmitError(
2803 'You added one or more relative #include paths (including "../").\n'
2804 'These shouldn\'t be used because they can be used to include headers\n'
2805 'from code that\'s not correctly specified as a dependency in the\n'
2806 'relevant BUILD.gn file(s).',
2807 error_descriptions))
2808
2809 return results
2810
Takeshi Yoshinoe387aa32017-08-02 13:16:132811
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202812def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2813 if not isinstance(key, ast.Str):
2814 return 'Key at line %d must be a string literal' % key.lineno
2815 if not isinstance(value, ast.Dict):
2816 return 'Value at line %d must be a dict' % value.lineno
2817 if len(value.keys) != 1:
2818 return 'Dict at line %d must have single entry' % value.lineno
2819 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2820 return (
2821 'Entry at line %d must have a string literal \'filepath\' as key' %
2822 value.lineno)
2823 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132824
Takeshi Yoshinoe387aa32017-08-02 13:16:132825
Sergey Ulanov4af16052018-11-08 02:41:462826def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202827 if not isinstance(key, ast.Str):
2828 return 'Key at line %d must be a string literal' % key.lineno
2829 if not isinstance(value, ast.List):
2830 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462831 for element in value.elts:
2832 if not isinstance(element, ast.Str):
2833 return 'Watchlist elements on line %d is not a string' % key.lineno
2834 if not email_regex.match(element.s):
2835 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2836 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202837 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132838
Takeshi Yoshinoe387aa32017-08-02 13:16:132839
Sergey Ulanov4af16052018-11-08 02:41:462840def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202841 mismatch_template = (
2842 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2843 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132844
Sergey Ulanov4af16052018-11-08 02:41:462845 email_regex = input_api.re.compile(
2846 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2847
2848 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202849 i = 0
2850 last_key = ''
2851 while True:
2852 if i >= len(wd_dict.keys):
2853 if i >= len(w_dict.keys):
2854 return None
2855 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2856 elif i >= len(w_dict.keys):
2857 return (
2858 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132859
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202860 wd_key = wd_dict.keys[i]
2861 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132862
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202863 result = _CheckWatchlistDefinitionsEntrySyntax(
2864 wd_key, wd_dict.values[i], ast)
2865 if result is not None:
2866 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132867
Sergey Ulanov4af16052018-11-08 02:41:462868 result = _CheckWatchlistsEntrySyntax(
2869 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202870 if result is not None:
2871 return 'Bad entry in WATCHLISTS dict: %s' % result
2872
2873 if wd_key.s != w_key.s:
2874 return mismatch_template % (
2875 '%s at line %d' % (wd_key.s, wd_key.lineno),
2876 '%s at line %d' % (w_key.s, w_key.lineno))
2877
2878 if wd_key.s < last_key:
2879 return (
2880 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2881 (wd_key.lineno, w_key.lineno))
2882 last_key = wd_key.s
2883
2884 i = i + 1
2885
2886
Sergey Ulanov4af16052018-11-08 02:41:462887def _CheckWATCHLISTSSyntax(expression, input_api):
2888 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202889 if not isinstance(expression, ast.Expression):
2890 return 'WATCHLISTS file must contain a valid expression'
2891 dictionary = expression.body
2892 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2893 return 'WATCHLISTS file must have single dict with exactly two entries'
2894
2895 first_key = dictionary.keys[0]
2896 first_value = dictionary.values[0]
2897 second_key = dictionary.keys[1]
2898 second_value = dictionary.values[1]
2899
2900 if (not isinstance(first_key, ast.Str) or
2901 first_key.s != 'WATCHLIST_DEFINITIONS' or
2902 not isinstance(first_value, ast.Dict)):
2903 return (
2904 'The first entry of the dict in WATCHLISTS file must be '
2905 'WATCHLIST_DEFINITIONS dict')
2906
2907 if (not isinstance(second_key, ast.Str) or
2908 second_key.s != 'WATCHLISTS' or
2909 not isinstance(second_value, ast.Dict)):
2910 return (
2911 'The second entry of the dict in WATCHLISTS file must be '
2912 'WATCHLISTS dict')
2913
Sergey Ulanov4af16052018-11-08 02:41:462914 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132915
2916
2917def _CheckWATCHLISTS(input_api, output_api):
2918 for f in input_api.AffectedFiles(include_deletes=False):
2919 if f.LocalPath() == 'WATCHLISTS':
2920 contents = input_api.ReadFile(f, 'r')
2921
2922 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202923 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132924 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202925 # Get an AST tree for it and scan the tree for detailed style checking.
2926 expression = input_api.ast.parse(
2927 contents, filename='WATCHLISTS', mode='eval')
2928 except ValueError as e:
2929 return [output_api.PresubmitError(
2930 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2931 except SyntaxError as e:
2932 return [output_api.PresubmitError(
2933 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2934 except TypeError as e:
2935 return [output_api.PresubmitError(
2936 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132937
Sergey Ulanov4af16052018-11-08 02:41:462938 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202939 if result is not None:
2940 return [output_api.PresubmitError(result)]
2941 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132942
2943 return []
2944
2945
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192946def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2947 """Checks that newly added header files have corresponding GN changes.
2948 Note that this is only a heuristic. To be precise, run script:
2949 build/check_gn_headers.py.
2950 """
2951
2952 def headers(f):
2953 return input_api.FilterSourceFile(
2954 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2955
2956 new_headers = []
2957 for f in input_api.AffectedSourceFiles(headers):
2958 if f.Action() != 'A':
2959 continue
2960 new_headers.append(f.LocalPath())
2961
2962 def gn_files(f):
2963 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2964
2965 all_gn_changed_contents = ''
2966 for f in input_api.AffectedSourceFiles(gn_files):
2967 for _, line in f.ChangedContents():
2968 all_gn_changed_contents += line
2969
2970 problems = []
2971 for header in new_headers:
2972 basename = input_api.os_path.basename(header)
2973 if basename not in all_gn_changed_contents:
2974 problems.append(header)
2975
2976 if problems:
2977 return [output_api.PresubmitPromptWarning(
2978 'Missing GN changes for new header files', items=sorted(problems),
2979 long_text='Please double check whether newly added header files need '
2980 'corresponding changes in gn or gni files.\nThis checking is only a '
2981 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2982 'Read https://crbug.com/661774 for more info.')]
2983 return []
2984
2985
Michael Giuffridad3bc8672018-10-25 22:48:022986def _CheckCorrectProductNameInMessages(input_api, output_api):
2987 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2988
2989 This assumes we won't intentionally reference one product from the other
2990 product.
2991 """
2992 all_problems = []
2993 test_cases = [{
2994 "filename_postfix": "google_chrome_strings.grd",
2995 "correct_name": "Chrome",
2996 "incorrect_name": "Chromium",
2997 }, {
2998 "filename_postfix": "chromium_strings.grd",
2999 "correct_name": "Chromium",
3000 "incorrect_name": "Chrome",
3001 }]
3002
3003 for test_case in test_cases:
3004 problems = []
3005 filename_filter = lambda x: x.LocalPath().endswith(
3006 test_case["filename_postfix"])
3007
3008 # Check each new line. Can yield false positives in multiline comments, but
3009 # easier than trying to parse the XML because messages can have nested
3010 # children, and associating message elements with affected lines is hard.
3011 for f in input_api.AffectedSourceFiles(filename_filter):
3012 for line_num, line in f.ChangedContents():
3013 if "<message" in line or "<!--" in line or "-->" in line:
3014 continue
3015 if test_case["incorrect_name"] in line:
3016 problems.append(
3017 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3018
3019 if problems:
3020 message = (
3021 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3022 % (test_case["correct_name"], test_case["correct_name"],
3023 test_case["incorrect_name"]))
3024 all_problems.append(
3025 output_api.PresubmitPromptWarning(message, items=problems))
3026
3027 return all_problems
3028
3029
dgnaa68d5e2015-06-10 10:08:223030def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573031 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223032 results = []
dgnaa68d5e2015-06-10 10:08:223033 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223034 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293035 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063036 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3037 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423038 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183039 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573040 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3041 return results
3042
3043def _AndroidSpecificOnCommitChecks(input_api, output_api):
3044 """Groups commit checks that target android code."""
3045 results = []
3046 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223047 return results
3048
3049
[email protected]22c9bd72011-03-27 16:47:393050def _CommonChecks(input_api, output_api):
3051 """Checks common to both upload and commit."""
3052 results = []
3053 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383054 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543055 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083056
3057 author = input_api.change.author_email
3058 if author and author not in _KNOWN_ROBOTS:
3059 results.extend(
3060 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3061
[email protected]55459852011-08-10 15:17:193062 results.extend(
[email protected]760deea2013-12-10 19:33:493063 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233064 results.extend(
3065 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543066 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183067 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343068 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523069 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223070 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443071 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593072 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063073 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123074 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183075 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223076 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303077 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493078 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033079 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493080 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443081 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273082 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073083 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543084 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443085 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393086 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553087 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043088 results.extend(
3089 input_api.canned_checks.CheckChangeHasNoTabs(
3090 input_api,
3091 output_api,
3092 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403093 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163094 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083095 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243096 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3097 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473098 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043099 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053100 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143101 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233102 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433103 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403104 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153105 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173106 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503107 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363108 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133109 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433110 results.extend(input_api.RunTests(
3111 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143112 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023113 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243114
Vaclav Brozekcdc7defb2018-03-20 09:54:353115 for f in input_api.AffectedFiles():
3116 path, name = input_api.os_path.split(f.LocalPath())
3117 if name == 'PRESUBMIT.py':
3118 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003119 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3120 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073121 # The PRESUBMIT.py file (and the directory containing it) might
3122 # have been affected by being moved or removed, so only try to
3123 # run the tests if they still exist.
3124 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3125 input_api, output_api, full_path,
3126 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393127 return results
[email protected]1f7b4172010-01-28 01:17:343128
[email protected]b337cb5b2011-01-23 21:24:053129
[email protected]b8079ae4a2012-12-05 19:56:493130def _CheckPatchFiles(input_api, output_api):
3131 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3132 if f.LocalPath().endswith(('.orig', '.rej'))]
3133 if problems:
3134 return [output_api.PresubmitError(
3135 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033136 else:
3137 return []
[email protected]b8079ae4a2012-12-05 19:56:493138
3139
Kent Tamura5a8755d2017-06-29 23:37:073140def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213141 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3142 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3143 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073144 include_re = input_api.re.compile(
3145 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3146 extension_re = input_api.re.compile(r'\.[a-z]+$')
3147 errors = []
3148 for f in input_api.AffectedFiles():
3149 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3150 continue
3151 found_line_number = None
3152 found_macro = None
3153 for line_num, line in f.ChangedContents():
3154 match = macro_re.search(line)
3155 if match:
3156 found_line_number = line_num
3157 found_macro = match.group(2)
3158 break
3159 if not found_line_number:
3160 continue
3161
3162 found_include = False
3163 for line in f.NewContents():
3164 if include_re.search(line):
3165 found_include = True
3166 break
3167 if found_include:
3168 continue
3169
3170 if not f.LocalPath().endswith('.h'):
3171 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3172 try:
3173 content = input_api.ReadFile(primary_header_path, 'r')
3174 if include_re.search(content):
3175 continue
3176 except IOError:
3177 pass
3178 errors.append('%s:%d %s macro is used without including build/'
3179 'build_config.h.'
3180 % (f.LocalPath(), found_line_number, found_macro))
3181 if errors:
3182 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3183 return []
3184
3185
[email protected]b00342e7f2013-03-26 16:21:543186def _DidYouMeanOSMacro(bad_macro):
3187 try:
3188 return {'A': 'OS_ANDROID',
3189 'B': 'OS_BSD',
3190 'C': 'OS_CHROMEOS',
3191 'F': 'OS_FREEBSD',
3192 'L': 'OS_LINUX',
3193 'M': 'OS_MACOSX',
3194 'N': 'OS_NACL',
3195 'O': 'OS_OPENBSD',
3196 'P': 'OS_POSIX',
3197 'S': 'OS_SOLARIS',
3198 'W': 'OS_WIN'}[bad_macro[3].upper()]
3199 except KeyError:
3200 return ''
3201
3202
3203def _CheckForInvalidOSMacrosInFile(input_api, f):
3204 """Check for sensible looking, totally invalid OS macros."""
3205 preprocessor_statement = input_api.re.compile(r'^\s*#')
3206 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3207 results = []
3208 for lnum, line in f.ChangedContents():
3209 if preprocessor_statement.search(line):
3210 for match in os_macro.finditer(line):
3211 if not match.group(1) in _VALID_OS_MACROS:
3212 good = _DidYouMeanOSMacro(match.group(1))
3213 did_you_mean = ' (did you mean %s?)' % good if good else ''
3214 results.append(' %s:%d %s%s' % (f.LocalPath(),
3215 lnum,
3216 match.group(1),
3217 did_you_mean))
3218 return results
3219
3220
3221def _CheckForInvalidOSMacros(input_api, output_api):
3222 """Check all affected files for invalid OS macros."""
3223 bad_macros = []
tzik3f295992018-12-04 20:32:233224 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473225 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543226 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3227
3228 if not bad_macros:
3229 return []
3230
3231 return [output_api.PresubmitError(
3232 'Possibly invalid OS macro[s] found. Please fix your code\n'
3233 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3234
lliabraa35bab3932014-10-01 12:16:443235
3236def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3237 """Check all affected files for invalid "if defined" macros."""
3238 ALWAYS_DEFINED_MACROS = (
3239 "TARGET_CPU_PPC",
3240 "TARGET_CPU_PPC64",
3241 "TARGET_CPU_68K",
3242 "TARGET_CPU_X86",
3243 "TARGET_CPU_ARM",
3244 "TARGET_CPU_MIPS",
3245 "TARGET_CPU_SPARC",
3246 "TARGET_CPU_ALPHA",
3247 "TARGET_IPHONE_SIMULATOR",
3248 "TARGET_OS_EMBEDDED",
3249 "TARGET_OS_IPHONE",
3250 "TARGET_OS_MAC",
3251 "TARGET_OS_UNIX",
3252 "TARGET_OS_WIN32",
3253 )
3254 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3255 results = []
3256 for lnum, line in f.ChangedContents():
3257 for match in ifdef_macro.finditer(line):
3258 if match.group(1) in ALWAYS_DEFINED_MACROS:
3259 always_defined = ' %s is always defined. ' % match.group(1)
3260 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3261 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3262 lnum,
3263 always_defined,
3264 did_you_mean))
3265 return results
3266
3267
3268def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3269 """Check all affected files for invalid "if defined" macros."""
3270 bad_macros = []
3271 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213272 if f.LocalPath().startswith('third_party/sqlite/'):
3273 continue
lliabraa35bab3932014-10-01 12:16:443274 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3275 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3276
3277 if not bad_macros:
3278 return []
3279
3280 return [output_api.PresubmitError(
3281 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3282 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3283 bad_macros)]
3284
3285
mlamouria82272622014-09-16 18:45:043286def _CheckForIPCRules(input_api, output_api):
3287 """Check for same IPC rules described in
3288 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3289 """
3290 base_pattern = r'IPC_ENUM_TRAITS\('
3291 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3292 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3293
3294 problems = []
3295 for f in input_api.AffectedSourceFiles(None):
3296 local_path = f.LocalPath()
3297 if not local_path.endswith('.h'):
3298 continue
3299 for line_number, line in f.ChangedContents():
3300 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3301 problems.append(
3302 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3303
3304 if problems:
3305 return [output_api.PresubmitPromptWarning(
3306 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3307 else:
3308 return []
3309
[email protected]b00342e7f2013-03-26 16:21:543310
Stephen Martinis97a394142018-06-07 23:06:053311def _CheckForLongPathnames(input_api, output_api):
3312 """Check to make sure no files being submitted have long paths.
3313 This causes issues on Windows.
3314 """
3315 problems = []
3316 for f in input_api.AffectedSourceFiles(None):
3317 local_path = f.LocalPath()
3318 # Windows has a path limit of 260 characters. Limit path length to 200 so
3319 # that we have some extra for the prefix on dev machines and the bots.
3320 if len(local_path) > 200:
3321 problems.append(local_path)
3322
3323 if problems:
3324 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3325 else:
3326 return []
3327
3328
Daniel Bratell8ba52722018-03-02 16:06:143329def _CheckForIncludeGuards(input_api, output_api):
3330 """Check that header files have proper guards against multiple inclusion.
3331 If a file should not have such guards (and it probably should) then it
3332 should include the string "no-include-guard-because-multiply-included".
3333 """
Daniel Bratell6a75baef62018-06-04 10:04:453334 def is_chromium_header_file(f):
3335 # We only check header files under the control of the Chromium
3336 # project. That is, those outside third_party apart from
3337 # third_party/blink.
3338 file_with_path = input_api.os_path.normpath(f.LocalPath())
3339 return (file_with_path.endswith('.h') and
3340 (not file_with_path.startswith('third_party') or
3341 file_with_path.startswith(
3342 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143343
3344 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343345 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143346
3347 errors = []
3348
Daniel Bratell6a75baef62018-06-04 10:04:453349 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143350 guard_name = None
3351 guard_line_number = None
3352 seen_guard_end = False
3353
3354 file_with_path = input_api.os_path.normpath(f.LocalPath())
3355 base_file_name = input_api.os_path.splitext(
3356 input_api.os_path.basename(file_with_path))[0]
3357 upper_base_file_name = base_file_name.upper()
3358
3359 expected_guard = replace_special_with_underscore(
3360 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143361
3362 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573363 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3364 # are too many (1000+) files with slight deviations from the
3365 # coding style. The most important part is that the include guard
3366 # is there, and that it's unique, not the name so this check is
3367 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143368 #
3369 # As code becomes more uniform, this could be made stricter.
3370
3371 guard_name_pattern_list = [
3372 # Anything with the right suffix (maybe with an extra _).
3373 r'\w+_H__?',
3374
Daniel Bratell39b5b062018-05-16 18:09:573375 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143376 r'\w+_h',
3377
3378 # Anything including the uppercase name of the file.
3379 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3380 upper_base_file_name)) + r'\w*',
3381 ]
3382 guard_name_pattern = '|'.join(guard_name_pattern_list)
3383 guard_pattern = input_api.re.compile(
3384 r'#ifndef\s+(' + guard_name_pattern + ')')
3385
3386 for line_number, line in enumerate(f.NewContents()):
3387 if 'no-include-guard-because-multiply-included' in line:
3388 guard_name = 'DUMMY' # To not trigger check outside the loop.
3389 break
3390
3391 if guard_name is None:
3392 match = guard_pattern.match(line)
3393 if match:
3394 guard_name = match.group(1)
3395 guard_line_number = line_number
3396
Daniel Bratell39b5b062018-05-16 18:09:573397 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453398 # don't match the chromium style guide, but new files should
3399 # get it right.
3400 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573401 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143402 errors.append(output_api.PresubmitPromptWarning(
3403 'Header using the wrong include guard name %s' % guard_name,
3404 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573405 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143406 else:
3407 # The line after #ifndef should have a #define of the same name.
3408 if line_number == guard_line_number + 1:
3409 expected_line = '#define %s' % guard_name
3410 if line != expected_line:
3411 errors.append(output_api.PresubmitPromptWarning(
3412 'Missing "%s" for include guard' % expected_line,
3413 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3414 'Expected: %r\nGot: %r' % (expected_line, line)))
3415
3416 if not seen_guard_end and line == '#endif // %s' % guard_name:
3417 seen_guard_end = True
3418 elif seen_guard_end:
3419 if line.strip() != '':
3420 errors.append(output_api.PresubmitPromptWarning(
3421 'Include guard %s not covering the whole file' % (
3422 guard_name), [f.LocalPath()]))
3423 break # Nothing else to check and enough to warn once.
3424
3425 if guard_name is None:
3426 errors.append(output_api.PresubmitPromptWarning(
3427 'Missing include guard %s' % expected_guard,
3428 [f.LocalPath()],
3429 'Missing include guard in %s\n'
3430 'Recommended name: %s\n'
3431 'This check can be disabled by having the string\n'
3432 'no-include-guard-because-multiply-included in the header.' %
3433 (f.LocalPath(), expected_guard)))
3434
3435 return errors
3436
3437
mostynbb639aca52015-01-07 20:31:233438def _CheckForWindowsLineEndings(input_api, output_api):
3439 """Check source code and known ascii text files for Windows style line
3440 endings.
3441 """
earthdok1b5e0ee2015-03-10 15:19:103442 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233443
3444 file_inclusion_pattern = (
3445 known_text_files,
3446 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3447 )
3448
mostynbb639aca52015-01-07 20:31:233449 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533450 source_file_filter = lambda f: input_api.FilterSourceFile(
3451 f, white_list=file_inclusion_pattern, black_list=None)
3452 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503453 include_file = False
3454 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233455 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503456 include_file = True
3457 if include_file:
3458 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233459
3460 if problems:
3461 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3462 'these files to contain Windows style line endings?\n' +
3463 '\n'.join(problems))]
3464
3465 return []
3466
3467
Vaclav Brozekd5de76a2018-03-17 07:57:503468def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133469 """Checks that all source files use SYSLOG properly."""
3470 syslog_files = []
3471 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563472 for line_number, line in f.ChangedContents():
3473 if 'SYSLOG' in line:
3474 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3475
pastarmovj89f7ee12016-09-20 14:58:133476 if syslog_files:
3477 return [output_api.PresubmitPromptWarning(
3478 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3479 ' calls.\nFiles to check:\n', items=syslog_files)]
3480 return []
3481
3482
[email protected]1f7b4172010-01-28 01:17:343483def CheckChangeOnUpload(input_api, output_api):
3484 results = []
3485 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473486 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283487 results.extend(
jam93a6ee792017-02-08 23:59:223488 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193489 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223490 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133491 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163492 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533493 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193494 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543495 return results
[email protected]ca8d1982009-02-19 16:33:123496
3497
[email protected]1bfb8322014-04-23 01:02:413498def GetTryServerMasterForBot(bot):
3499 """Returns the Try Server master for the given bot.
3500
[email protected]0bb112362014-07-26 04:38:323501 It tries to guess the master from the bot name, but may still fail
3502 and return None. There is no longer a default master.
3503 """
3504 # Potentially ambiguous bot names are listed explicitly.
3505 master_map = {
tandriie5587792016-07-14 00:34:503506 'chromium_presubmit': 'master.tryserver.chromium.linux',
3507 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413508 }
[email protected]0bb112362014-07-26 04:38:323509 master = master_map.get(bot)
3510 if not master:
wnwen4fbaab82016-05-25 12:54:363511 if 'android' in bot:
tandriie5587792016-07-14 00:34:503512 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363513 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503514 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323515 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503516 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323517 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503518 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323519 return master
[email protected]1bfb8322014-04-23 01:02:413520
3521
[email protected]ca8d1982009-02-19 16:33:123522def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543523 results = []
[email protected]1f7b4172010-01-28 01:17:343524 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573525 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543526 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273527 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343528 input_api,
3529 output_api,
[email protected]2fdd1f362013-01-16 03:56:033530 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273531
jam93a6ee792017-02-08 23:59:223532 results.extend(
3533 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543534 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3535 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413536 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3537 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543538 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143539
3540
3541def _CheckTranslationScreenshots(input_api, output_api):
3542 PART_FILE_TAG = "part"
3543 import os
3544 import sys
3545 from io import StringIO
3546
3547 try:
3548 old_sys_path = sys.path
3549 sys.path = sys.path + [input_api.os_path.join(
3550 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3551 import grit.grd_reader
3552 import grit.node.message
3553 import grit.util
3554 finally:
3555 sys.path = old_sys_path
3556
3557 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3558 """Load the grd file and return a dict of message ids to messages.
3559
3560 Ignores any nested grdp files pointed by <part> tag.
3561 """
3562 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3563 stop_after=None, first_ids_file=None,
3564 debug=False, defines=None,
3565 tags_to_ignore=set([PART_FILE_TAG]))
3566 return {
3567 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3568 grit.node.message.MessageNode)
3569 }
3570
3571 def _GetGrdpMessagesFromString(grdp_string):
3572 """Parses the contents of a grdp file given in grdp_string.
3573
3574 grd_reader can't parse grdp files directly. Instead, this creates a
3575 temporary directory with a grd file pointing to the grdp file, and loads the
3576 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3577 """
3578 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3579 <grit latest_public_release="1" current_release="1">
3580 <release seq="1">
3581 <messages>
3582 <part file="sub.grdp" />
3583 </messages>
3584 </release>
3585 </grit>
3586 """
3587 with grit.util.TempDir({'main.grd': WRAPPER,
3588 'sub.grdp': grdp_string}) as temp_dir:
3589 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3590
3591 new_or_added_paths = set(f.LocalPath()
3592 for f in input_api.AffectedFiles()
3593 if (f.Action() == 'A' or f.Action() == 'M'))
3594 removed_paths = set(f.LocalPath()
3595 for f in input_api.AffectedFiles(include_deletes=True)
3596 if f.Action() == 'D')
3597
3598 affected_grds = [f for f in input_api.AffectedFiles()
3599 if (f.LocalPath().endswith('.grd') or
3600 f.LocalPath().endswith('.grdp'))]
3601 affected_png_paths = [f.AbsoluteLocalPath()
3602 for f in input_api.AffectedFiles()
3603 if (f.LocalPath().endswith('.png'))]
3604
3605 # Check for screenshots. Developers can upload screenshots using
3606 # tools/translation/upload_screenshots.py which finds and uploads
3607 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3608 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3609 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3610 #
3611 # The logic here is as follows:
3612 #
3613 # - If the CL has a .png file under the screenshots directory for a grd
3614 # file, warn the developer. Actual images should never be checked into the
3615 # Chrome repo.
3616 #
3617 # - If the CL contains modified or new messages in grd files and doesn't
3618 # contain the corresponding .sha1 files, warn the developer to add images
3619 # and upload them via tools/translation/upload_screenshots.py.
3620 #
3621 # - If the CL contains modified or new messages in grd files and the
3622 # corresponding .sha1 files, everything looks good.
3623 #
3624 # - If the CL contains removed messages in grd files but the corresponding
3625 # .sha1 files aren't removed, warn the developer to remove them.
3626 unnecessary_screenshots = []
3627 missing_sha1 = []
3628 unnecessary_sha1_files = []
3629
3630
3631 def _CheckScreenshotAdded(screenshots_dir, message_id):
3632 sha1_path = input_api.os_path.join(
3633 screenshots_dir, message_id + '.png.sha1')
3634 if sha1_path not in new_or_added_paths:
3635 missing_sha1.append(sha1_path)
3636
3637
3638 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3639 sha1_path = input_api.os_path.join(
3640 screenshots_dir, message_id + '.png.sha1')
3641 if sha1_path not in removed_paths:
3642 unnecessary_sha1_files.append(sha1_path)
3643
3644
3645 for f in affected_grds:
3646 file_path = f.LocalPath()
3647 old_id_to_msg_map = {}
3648 new_id_to_msg_map = {}
3649 if file_path.endswith('.grdp'):
3650 if f.OldContents():
3651 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393652 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143653 if f.NewContents():
3654 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393655 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143656 else:
3657 if f.OldContents():
3658 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393659 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143660 if f.NewContents():
3661 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393662 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143663
3664 # Compute added, removed and modified message IDs.
3665 old_ids = set(old_id_to_msg_map)
3666 new_ids = set(new_id_to_msg_map)
3667 added_ids = new_ids - old_ids
3668 removed_ids = old_ids - new_ids
3669 modified_ids = set([])
3670 for key in old_ids.intersection(new_ids):
3671 if (old_id_to_msg_map[key].FormatXml()
3672 != new_id_to_msg_map[key].FormatXml()):
3673 modified_ids.add(key)
3674
3675 grd_name, ext = input_api.os_path.splitext(
3676 input_api.os_path.basename(file_path))
3677 screenshots_dir = input_api.os_path.join(
3678 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3679
3680 # Check the screenshot directory for .png files. Warn if there is any.
3681 for png_path in affected_png_paths:
3682 if png_path.startswith(screenshots_dir):
3683 unnecessary_screenshots.append(png_path)
3684
3685 for added_id in added_ids:
3686 _CheckScreenshotAdded(screenshots_dir, added_id)
3687
3688 for modified_id in modified_ids:
3689 _CheckScreenshotAdded(screenshots_dir, modified_id)
3690
3691 for removed_id in removed_ids:
3692 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3693
3694 results = []
3695 if unnecessary_screenshots:
3696 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393697 'Do not include actual screenshots in the changelist. Run '
3698 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143699 sorted(unnecessary_screenshots)))
3700
3701 if missing_sha1:
3702 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393703 'You are adding or modifying UI strings.\n'
3704 'To ensure the best translations, take screenshots of the relevant UI '
3705 '(https://g.co/chrome/translation) and add these files to your '
3706 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143707
3708 if unnecessary_sha1_files:
3709 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393710 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143711 sorted(unnecessary_sha1_files)))
3712
3713 return results