blob: c0324ab809eee63b845e7db0e0041b71edbe4ba3 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-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]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
vapierb2053f542017-03-09 19:46:1028 r"tools[\\\/]md_browser[\\\/].*\.css$",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d19842009-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
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5344 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4750 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4951 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0852 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4953 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4454)
[email protected]ca8d19842009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
jif65398702016-10-27 10:19:48143 (
144 r"/\s+UTF8String\s*]",
145 (
146 'The use of -[NSString UTF8String] is dangerous as it can return null',
147 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
148 'Please use |SysNSStringToUTF8| instead.',
149 ),
150 True,
151 ),
[email protected]127f18ec2012-06-16 05:05:59152)
153
154
155_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20156 # Make sure that gtest's FRIEND_TEST() macro is not used; the
157 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30158 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20159 (
thomasandersone7caaa9b2017-03-29 19:22:53160 r'\bNULL\b',
161 (
162 'New code should not use NULL. Use nullptr instead.',
163 ),
164 True,
165 (),
166 ),
167 (
[email protected]23e6cbc2012-06-16 18:51:20168 'FRIEND_TEST(',
169 (
[email protected]e3c945502012-06-26 20:01:49170 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20171 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
172 ),
173 False,
[email protected]7345da02012-11-27 14:31:49174 (),
[email protected]23e6cbc2012-06-16 18:51:20175 ),
176 (
thomasanderson4b569052016-09-14 20:15:53177 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
178 (
179 'Chrome clients wishing to select events on X windows should use',
180 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
181 'you are selecting events from the GPU process, or if you are using',
182 'an XDisplay other than gfx::GetXDisplay().',
183 ),
184 True,
185 (
186 r"^ui[\\\/]gl[\\\/].*\.cc$",
187 r"^media[\\\/]gpu[\\\/].*\.cc$",
188 r"^gpu[\\\/].*\.cc$",
189 ),
190 ),
191 (
thomasandersone043e3ce2017-06-08 00:43:20192 r'XInternAtom|xcb_intern_atom',
193 (
194 'Use ui::GetAtom() or ui::X11AtomCache::GetAtom() instead of',
195 'interning atoms directly.',
196 ),
197 True,
198 (
199 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
200 ),
201 ),
202 (
[email protected]23e6cbc2012-06-16 18:51:20203 'ScopedAllowIO',
204 (
satoruxe1396f8a2017-06-01 06:40:39205 'New production code should not use ScopedAllowIO (using it in',
206 'browser tests is fine). Post a task to the blocking pool or the',
207 'FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20208 ),
[email protected]e3c945502012-06-26 20:01:49209 True,
[email protected]7345da02012-11-27 14:31:49210 (
satoruxe1396f8a2017-06-01 06:40:39211 r"^.*browser(|_)test[a-z_]*\.cc$",
hajimehoshi2acea432017-03-08 08:55:37212 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
rayb0088ee52017-04-26 22:35:08213 r"^base[\\\/]process[\\\/]internal_aix\.cc$",
nyad2c548b2015-12-09 03:22:32214 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10215 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22216 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31217 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
philipj3f9d5bde2014-08-28 14:09:09218 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49219 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
220 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41221 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
222 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25223 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
miu8e0e80c2017-05-31 03:35:57224 r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" +
225 r"standalone_cast_environment\.cc$",
jamesra03ae492014-10-03 04:26:48226 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
227 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01228 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25229 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
230 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
231 r"embedded_test_server\.cc$",
232 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
233 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54234 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16235 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53236 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
237 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45238 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
239 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
240 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
241 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
242 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49243 ),
[email protected]23e6cbc2012-06-16 18:51:20244 ),
[email protected]52657f62013-05-20 05:30:31245 (
tomhudsone2c14d552016-05-26 17:07:46246 'setMatrixClip',
247 (
248 'Overriding setMatrixClip() is prohibited; ',
249 'the base function is deprecated. ',
250 ),
251 True,
252 (),
253 ),
254 (
[email protected]52657f62013-05-20 05:30:31255 'SkRefPtr',
256 (
257 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22258 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31259 ),
260 True,
261 (),
262 ),
263 (
264 'SkAutoRef',
265 (
266 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22267 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31268 ),
269 True,
270 (),
271 ),
272 (
273 'SkAutoTUnref',
274 (
275 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22276 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31277 ),
278 True,
279 (),
280 ),
281 (
282 'SkAutoUnref',
283 (
284 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
285 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22286 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31287 ),
288 True,
289 (),
290 ),
[email protected]d89eec82013-12-03 14:10:59291 (
292 r'/HANDLE_EINTR\(.*close',
293 (
294 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
295 'descriptor will be closed, and it is incorrect to retry the close.',
296 'Either call close directly and ignore its return value, or wrap close',
297 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
298 ),
299 True,
300 (),
301 ),
302 (
303 r'/IGNORE_EINTR\((?!.*close)',
304 (
305 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
306 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
307 ),
308 True,
309 (
310 # Files that #define IGNORE_EINTR.
311 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
312 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
313 ),
314 ),
[email protected]ec5b3f02014-04-04 18:43:43315 (
316 r'/v8::Extension\(',
317 (
318 'Do not introduce new v8::Extensions into the code base, use',
319 'gin::Wrappable instead. See http://crbug.com/334679',
320 ),
321 True,
[email protected]f55c90ee62014-04-12 00:50:03322 (
joaodasilva718f87672014-08-30 09:25:49323 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03324 ),
[email protected]ec5b3f02014-04-04 18:43:43325 ),
skyostilf9469f72015-04-20 10:38:52326 (
jame2d1a952016-04-02 00:27:10327 '#pragma comment(lib,',
328 (
329 'Specify libraries to link with in build files and not in the source.',
330 ),
331 True,
332 (),
333 ),
fdorayc4ac18d2017-05-01 21:39:59334 (
335 'BrowserThread::GetBlockingPool',
336 (
337 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
338 'mapping between both APIs in content/public/browser/browser_thread.h.',
339 'For questions, contact base/task_scheduler/OWNERS.',
340 ),
341 True,
342 (),
343 ),
gabd52c912a2017-05-11 04:15:59344 (
gabd52c912a2017-05-11 04:15:59345 'base::SequenceChecker',
346 (
347 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
348 ),
349 False,
350 (),
351 ),
352 (
353 'base::ThreadChecker',
354 (
355 'Consider using THREAD_CHECKER macros instead of the class directly.',
356 ),
357 False,
358 (),
359 ),
[email protected]127f18ec2012-06-16 05:05:59360)
361
wnwenbdc444e2016-05-25 13:44:15362
mlamouria82272622014-09-16 18:45:04363_IPC_ENUM_TRAITS_DEPRECATED = (
364 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
365 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
366
[email protected]127f18ec2012-06-16 05:05:59367
[email protected]b00342e7f2013-03-26 16:21:54368_VALID_OS_MACROS = (
369 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08370 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54371 'OS_ANDROID',
372 'OS_BSD',
373 'OS_CAT', # For testing.
374 'OS_CHROMEOS',
375 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37376 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54377 'OS_IOS',
378 'OS_LINUX',
379 'OS_MACOSX',
380 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21381 'OS_NACL_NONSFI',
382 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12383 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54384 'OS_OPENBSD',
385 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37386 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54387 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54388 'OS_WIN',
389)
390
391
agrievef32bcc72016-04-04 14:57:40392_ANDROID_SPECIFIC_PYDEPS_FILES = [
393 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04394 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58395 'build/secondary/third_party/android_platform/'
396 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19397 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40398]
399
wnwenbdc444e2016-05-25 13:44:15400
agrievef32bcc72016-04-04 14:57:40401_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40402]
403
wnwenbdc444e2016-05-25 13:44:15404
agrievef32bcc72016-04-04 14:57:40405_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
406
407
[email protected]55459852011-08-10 15:17:19408def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
409 """Attempts to prevent use of functions intended only for testing in
410 non-testing code. For now this is just a best-effort implementation
411 that ignores header files and may have some false positives. A
412 better implementation would probably need a proper C++ parser.
413 """
414 # We only scan .cc files and the like, as the declaration of
415 # for-testing functions in header files are hard to distinguish from
416 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44417 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19418
jochenc0d4808c2015-07-27 09:25:42419 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19420 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09421 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19422 exclusion_pattern = input_api.re.compile(
423 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
424 base_function_pattern, base_function_pattern))
425
426 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44427 black_list = (_EXCLUDED_PATHS +
428 _TEST_CODE_EXCLUDED_PATHS +
429 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19430 return input_api.FilterSourceFile(
431 affected_file,
432 white_list=(file_inclusion_pattern, ),
433 black_list=black_list)
434
435 problems = []
436 for f in input_api.AffectedSourceFiles(FilterFile):
437 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24438 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03439 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46440 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03441 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19442 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03443 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19444
445 if problems:
[email protected]f7051d52013-04-02 18:31:42446 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03447 else:
448 return []
[email protected]55459852011-08-10 15:17:19449
450
[email protected]10689ca2011-09-02 02:31:54451def _CheckNoIOStreamInHeaders(input_api, output_api):
452 """Checks to make sure no .h files include <iostream>."""
453 files = []
454 pattern = input_api.re.compile(r'^#include\s*<iostream>',
455 input_api.re.MULTILINE)
456 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
457 if not f.LocalPath().endswith('.h'):
458 continue
459 contents = input_api.ReadFile(f)
460 if pattern.search(contents):
461 files.append(f)
462
463 if len(files):
yolandyandaabc6d2016-04-18 18:29:39464 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06465 'Do not #include <iostream> in header files, since it inserts static '
466 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54467 '#include <ostream>. See http://crbug.com/94794',
468 files) ]
469 return []
470
471
[email protected]72df4e782012-06-21 16:28:18472def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52473 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18474 problems = []
475 for f in input_api.AffectedFiles():
476 if (not f.LocalPath().endswith(('.cc', '.mm'))):
477 continue
478
479 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04480 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18481 problems.append(' %s:%d' % (f.LocalPath(), line_num))
482
483 if not problems:
484 return []
485 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
486 '\n'.join(problems))]
487
488
danakj61c1aa22015-10-26 19:55:52489def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57490 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52491 errors = []
492 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
493 input_api.re.MULTILINE)
494 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
495 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
496 continue
497 for lnum, line in f.ChangedContents():
498 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17499 errors.append(output_api.PresubmitError(
500 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57501 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17502 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52503 return errors
504
505
mcasasb7440c282015-02-04 14:52:19506def _FindHistogramNameInLine(histogram_name, line):
507 """Tries to find a histogram name or prefix in a line."""
508 if not "affected-histogram" in line:
509 return histogram_name in line
510 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
511 # the histogram_name.
512 if not '"' in line:
513 return False
514 histogram_prefix = line.split('\"')[1]
515 return histogram_prefix in histogram_name
516
517
518def _CheckUmaHistogramChanges(input_api, output_api):
519 """Check that UMA histogram names in touched lines can still be found in other
520 lines of the patch or in histograms.xml. Note that this check would not catch
521 the reverse: changes in histograms.xml not matched in the code itself."""
522 touched_histograms = []
523 histograms_xml_modifications = []
524 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
525 for f in input_api.AffectedFiles():
526 # If histograms.xml itself is modified, keep the modified lines for later.
527 if f.LocalPath().endswith(('histograms.xml')):
528 histograms_xml_modifications = f.ChangedContents()
529 continue
530 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
531 continue
532 for line_num, line in f.ChangedContents():
533 found = pattern.search(line)
534 if found:
535 touched_histograms.append([found.group(1), f, line_num])
536
537 # Search for the touched histogram names in the local modifications to
538 # histograms.xml, and, if not found, on the base histograms.xml file.
539 unmatched_histograms = []
540 for histogram_info in touched_histograms:
541 histogram_name_found = False
542 for line_num, line in histograms_xml_modifications:
543 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
544 if histogram_name_found:
545 break
546 if not histogram_name_found:
547 unmatched_histograms.append(histogram_info)
548
eromanb90c82e7e32015-04-01 15:13:49549 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19550 problems = []
551 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49552 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19553 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45554 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19555 histogram_name_found = False
556 for line in histograms_xml:
557 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
558 if histogram_name_found:
559 break
560 if not histogram_name_found:
561 problems.append(' [%s:%d] %s' %
562 (f.LocalPath(), line_num, histogram_name))
563
564 if not problems:
565 return []
566 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
567 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49568 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19569
wnwenbdc444e2016-05-25 13:44:15570
yolandyandaabc6d2016-04-18 18:29:39571def _CheckFlakyTestUsage(input_api, output_api):
572 """Check that FlakyTest annotation is our own instead of the android one"""
573 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
574 files = []
575 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
576 if f.LocalPath().endswith('Test.java'):
577 if pattern.search(input_api.ReadFile(f)):
578 files.append(f)
579 if len(files):
580 return [output_api.PresubmitError(
581 'Use org.chromium.base.test.util.FlakyTest instead of '
582 'android.test.FlakyTest',
583 files)]
584 return []
mcasasb7440c282015-02-04 14:52:19585
wnwenbdc444e2016-05-25 13:44:15586
[email protected]8ea5d4b2011-09-13 21:49:22587def _CheckNoNewWStrings(input_api, output_api):
588 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27589 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22590 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20591 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57592 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34593 '/win/' in f.LocalPath() or
594 'chrome_elf' in f.LocalPath() or
595 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20596 continue
[email protected]8ea5d4b2011-09-13 21:49:22597
[email protected]a11dbe9b2012-08-07 01:32:58598 allowWString = False
[email protected]b5c24292011-11-28 14:38:20599 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58600 if 'presubmit: allow wstring' in line:
601 allowWString = True
602 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27603 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58604 allowWString = False
605 else:
606 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22607
[email protected]55463aa62011-10-12 00:48:27608 if not problems:
609 return []
610 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58611 ' If you are calling a cross-platform API that accepts a wstring, '
612 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27613 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22614
615
[email protected]2a8ac9c2011-10-19 17:20:44616def _CheckNoDEPSGIT(input_api, output_api):
617 """Make sure .DEPS.git is never modified manually."""
618 if any(f.LocalPath().endswith('.DEPS.git') for f in
619 input_api.AffectedFiles()):
620 return [output_api.PresubmitError(
621 'Never commit changes to .DEPS.git. This file is maintained by an\n'
622 'automated system based on what\'s in DEPS and your changes will be\n'
623 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34624 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44625 'for more information')]
626 return []
627
628
tandriief664692014-09-23 14:51:47629def _CheckValidHostsInDEPS(input_api, output_api):
630 """Checks that DEPS file deps are from allowed_hosts."""
631 # Run only if DEPS file has been modified to annoy fewer bystanders.
632 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
633 return []
634 # Outsource work to gclient verify
635 try:
636 input_api.subprocess.check_output(['gclient', 'verify'])
637 return []
638 except input_api.subprocess.CalledProcessError, error:
639 return [output_api.PresubmitError(
640 'DEPS file must have only git dependencies.',
641 long_text=error.output)]
642
643
[email protected]127f18ec2012-06-16 05:05:59644def _CheckNoBannedFunctions(input_api, output_api):
645 """Make sure that banned functions are not used."""
646 warnings = []
647 errors = []
648
wnwenbdc444e2016-05-25 13:44:15649 def IsBlacklisted(affected_file, blacklist):
650 local_path = affected_file.LocalPath()
651 for item in blacklist:
652 if input_api.re.match(item, local_path):
653 return True
654 return False
655
656 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
657 matched = False
658 if func_name[0:1] == '/':
659 regex = func_name[1:]
660 if input_api.re.search(regex, line):
661 matched = True
662 elif func_name in line:
dchenge07de812016-06-20 19:27:17663 matched = True
wnwenbdc444e2016-05-25 13:44:15664 if matched:
dchenge07de812016-06-20 19:27:17665 problems = warnings
wnwenbdc444e2016-05-25 13:44:15666 if error:
dchenge07de812016-06-20 19:27:17667 problems = errors
wnwenbdc444e2016-05-25 13:44:15668 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
669 for message_line in message:
670 problems.append(' %s' % message_line)
671
[email protected]127f18ec2012-06-16 05:05:59672 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
673 for f in input_api.AffectedFiles(file_filter=file_filter):
674 for line_num, line in f.ChangedContents():
675 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15676 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59677
678 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
679 for f in input_api.AffectedFiles(file_filter=file_filter):
680 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49681 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49682 if IsBlacklisted(f, excluded_paths):
683 continue
wnwenbdc444e2016-05-25 13:44:15684 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59685
686 result = []
687 if (warnings):
688 result.append(output_api.PresubmitPromptWarning(
689 'Banned functions were used.\n' + '\n'.join(warnings)))
690 if (errors):
691 result.append(output_api.PresubmitError(
692 'Banned functions were used.\n' + '\n'.join(errors)))
693 return result
694
695
[email protected]6c063c62012-07-11 19:11:06696def _CheckNoPragmaOnce(input_api, output_api):
697 """Make sure that banned functions are not used."""
698 files = []
699 pattern = input_api.re.compile(r'^#pragma\s+once',
700 input_api.re.MULTILINE)
701 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
702 if not f.LocalPath().endswith('.h'):
703 continue
704 contents = input_api.ReadFile(f)
705 if pattern.search(contents):
706 files.append(f)
707
708 if files:
709 return [output_api.PresubmitError(
710 'Do not use #pragma once in header files.\n'
711 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
712 files)]
713 return []
714
[email protected]127f18ec2012-06-16 05:05:59715
[email protected]e7479052012-09-19 00:26:12716def _CheckNoTrinaryTrueFalse(input_api, output_api):
717 """Checks to make sure we don't introduce use of foo ? true : false."""
718 problems = []
719 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
720 for f in input_api.AffectedFiles():
721 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
722 continue
723
724 for line_num, line in f.ChangedContents():
725 if pattern.match(line):
726 problems.append(' %s:%d' % (f.LocalPath(), line_num))
727
728 if not problems:
729 return []
730 return [output_api.PresubmitPromptWarning(
731 'Please consider avoiding the "? true : false" pattern if possible.\n' +
732 '\n'.join(problems))]
733
734
[email protected]55f9f382012-07-31 11:02:18735def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28736 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18737 change. Breaking - rules is an error, breaking ! rules is a
738 warning.
739 """
mohan.reddyf21db962014-10-16 12:26:47740 import sys
[email protected]55f9f382012-07-31 11:02:18741 # We need to wait until we have an input_api object and use this
742 # roundabout construct to import checkdeps because this file is
743 # eval-ed and thus doesn't have __file__.
744 original_sys_path = sys.path
745 try:
746 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47747 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18748 import checkdeps
749 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28750 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18751 from rules import Rule
752 finally:
753 # Restore sys.path to what it was before.
754 sys.path = original_sys_path
755
756 added_includes = []
rhalavati08acd232017-04-03 07:23:28757 added_imports = []
[email protected]55f9f382012-07-31 11:02:18758 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28759 if CppChecker.IsCppFile(f.LocalPath()):
760 changed_lines = [line for line_num, line in f.ChangedContents()]
761 added_includes.append([f.LocalPath(), changed_lines])
762 elif ProtoChecker.IsProtoFile(f.LocalPath()):
763 changed_lines = [line for line_num, line in f.ChangedContents()]
764 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18765
[email protected]26385172013-05-09 23:11:35766 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18767
768 error_descriptions = []
769 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28770 error_subjects = set()
771 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18772 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
773 added_includes):
774 description_with_path = '%s\n %s' % (path, rule_description)
775 if rule_type == Rule.DISALLOW:
776 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28777 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18778 else:
779 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28780 warning_subjects.add("#includes")
781
782 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
783 added_imports):
784 description_with_path = '%s\n %s' % (path, rule_description)
785 if rule_type == Rule.DISALLOW:
786 error_descriptions.append(description_with_path)
787 error_subjects.add("imports")
788 else:
789 warning_descriptions.append(description_with_path)
790 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18791
792 results = []
793 if error_descriptions:
794 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28795 'You added one or more %s that violate checkdeps rules.'
796 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18797 error_descriptions))
798 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42799 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28800 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18801 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28802 '%s? See relevant DEPS file(s) for details and contacts.' %
803 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18804 warning_descriptions))
805 return results
806
807
[email protected]fbcafe5a2012-08-08 15:31:22808def _CheckFilePermissions(input_api, output_api):
809 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15810 if input_api.platform == 'win32':
811 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29812 checkperms_tool = input_api.os_path.join(
813 input_api.PresubmitLocalPath(),
814 'tools', 'checkperms', 'checkperms.py')
815 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47816 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22817 for f in input_api.AffectedFiles():
818 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11819 try:
820 input_api.subprocess.check_output(args)
821 return []
822 except input_api.subprocess.CalledProcessError as error:
823 return [output_api.PresubmitError(
824 'checkperms.py failed:',
825 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22826
827
robertocn832f5992017-01-04 19:01:30828def _CheckTeamTags(input_api, output_api):
829 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
830 checkteamtags_tool = input_api.os_path.join(
831 input_api.PresubmitLocalPath(),
832 'tools', 'checkteamtags', 'checkteamtags.py')
833 args = [input_api.python_executable, checkteamtags_tool,
834 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22835 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30836 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
837 'OWNERS']
838 try:
839 if files:
840 input_api.subprocess.check_output(args + files)
841 return []
842 except input_api.subprocess.CalledProcessError as error:
843 return [output_api.PresubmitError(
844 'checkteamtags.py failed:',
845 long_text=error.output)]
846
847
[email protected]c8278b32012-10-30 20:35:49848def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
849 """Makes sure we don't include ui/aura/window_property.h
850 in header files.
851 """
852 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
853 errors = []
854 for f in input_api.AffectedFiles():
855 if not f.LocalPath().endswith('.h'):
856 continue
857 for line_num, line in f.ChangedContents():
858 if pattern.match(line):
859 errors.append(' %s:%d' % (f.LocalPath(), line_num))
860
861 results = []
862 if errors:
863 results.append(output_api.PresubmitError(
864 'Header files should not include ui/aura/window_property.h', errors))
865 return results
866
867
[email protected]cf9b78f2012-11-14 11:40:28868def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
869 """Checks that the lines in scope occur in the right order.
870
871 1. C system files in alphabetical order
872 2. C++ system files in alphabetical order
873 3. Project's .h files
874 """
875
876 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
877 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
878 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
879
880 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
881
882 state = C_SYSTEM_INCLUDES
883
884 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57885 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28886 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55887 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28888 for line_num, line in scope:
889 if c_system_include_pattern.match(line):
890 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55891 problem_linenums.append((line_num, previous_line_num,
892 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28893 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55894 problem_linenums.append((line_num, previous_line_num,
895 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28896 elif cpp_system_include_pattern.match(line):
897 if state == C_SYSTEM_INCLUDES:
898 state = CPP_SYSTEM_INCLUDES
899 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55900 problem_linenums.append((line_num, previous_line_num,
901 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28902 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55903 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28904 elif custom_include_pattern.match(line):
905 if state != CUSTOM_INCLUDES:
906 state = CUSTOM_INCLUDES
907 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55908 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28909 else:
brucedawson70fadb02015-06-30 17:47:55910 problem_linenums.append((line_num, previous_line_num,
911 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28912 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57913 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28914
915 warnings = []
brucedawson70fadb02015-06-30 17:47:55916 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57917 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55918 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28919 return warnings
920
921
[email protected]ac294a12012-12-06 16:38:43922def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28923 """Checks the #include order for the given file f."""
924
[email protected]2299dcf2012-11-15 19:56:24925 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30926 # Exclude the following includes from the check:
927 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
928 # specific order.
929 # 2) <atlbase.h>, "build/build_config.h"
930 excluded_include_pattern = input_api.re.compile(
931 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24932 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33933 # Match the final or penultimate token if it is xxxtest so we can ignore it
934 # when considering the special first include.
935 test_file_tag_pattern = input_api.re.compile(
936 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11937 if_pattern = input_api.re.compile(
938 r'\s*#\s*(if|elif|else|endif|define|undef).*')
939 # Some files need specialized order of includes; exclude such files from this
940 # check.
941 uncheckable_includes_pattern = input_api.re.compile(
942 r'\s*#include '
943 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28944
945 contents = f.NewContents()
946 warnings = []
947 line_num = 0
948
[email protected]ac294a12012-12-06 16:38:43949 # Handle the special first include. If the first include file is
950 # some/path/file.h, the corresponding including file can be some/path/file.cc,
951 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
952 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33953 # If the included file is some/path/file_platform.h the including file could
954 # also be some/path/file_xxxtest_platform.h.
955 including_file_base_name = test_file_tag_pattern.sub(
956 '', input_api.os_path.basename(f.LocalPath()))
957
[email protected]ac294a12012-12-06 16:38:43958 for line in contents:
959 line_num += 1
960 if system_include_pattern.match(line):
961 # No special first include -> process the line again along with normal
962 # includes.
963 line_num -= 1
964 break
965 match = custom_include_pattern.match(line)
966 if match:
967 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33968 header_basename = test_file_tag_pattern.sub(
969 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
970
971 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24972 # No special first include -> process the line again along with normal
973 # includes.
974 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43975 break
[email protected]cf9b78f2012-11-14 11:40:28976
977 # Split into scopes: Each region between #if and #endif is its own scope.
978 scopes = []
979 current_scope = []
980 for line in contents[line_num:]:
981 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11982 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54983 continue
[email protected]2309b0fa02012-11-16 12:18:27984 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28985 scopes.append(current_scope)
986 current_scope = []
[email protected]962f117e2012-11-22 18:11:56987 elif ((system_include_pattern.match(line) or
988 custom_include_pattern.match(line)) and
989 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28990 current_scope.append((line_num, line))
991 scopes.append(current_scope)
992
993 for scope in scopes:
994 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
995 changed_linenums))
996 return warnings
997
998
999def _CheckIncludeOrder(input_api, output_api):
1000 """Checks that the #include order is correct.
1001
1002 1. The corresponding header for source files.
1003 2. C system files in alphabetical order
1004 3. C++ system files in alphabetical order
1005 4. Project's .h files in alphabetical order
1006
[email protected]ac294a12012-12-06 16:38:431007 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
1008 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:281009 """
[email protected]e120b012014-08-15 19:08:351010 def FileFilterIncludeOrder(affected_file):
1011 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
1012 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:281013
1014 warnings = []
[email protected]e120b012014-08-15 19:08:351015 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:081016 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:431017 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
1018 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:281019
1020 results = []
1021 if warnings:
[email protected]f7051d52013-04-02 18:31:421022 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:531023 warnings))
[email protected]cf9b78f2012-11-14 11:40:281024 return results
1025
1026
[email protected]70ca77752012-11-20 03:45:031027def _CheckForVersionControlConflictsInFile(input_api, f):
1028 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1029 errors = []
1030 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231031 if f.LocalPath().endswith('.md'):
1032 # First-level headers in markdown look a lot like version control
1033 # conflict markers. http://daringfireball.net/projects/markdown/basics
1034 continue
[email protected]70ca77752012-11-20 03:45:031035 if pattern.match(line):
1036 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1037 return errors
1038
1039
1040def _CheckForVersionControlConflicts(input_api, output_api):
1041 """Usually this is not intentional and will cause a compile failure."""
1042 errors = []
1043 for f in input_api.AffectedFiles():
1044 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1045
1046 results = []
1047 if errors:
1048 results.append(output_api.PresubmitError(
1049 'Version control conflict markers found, please resolve.', errors))
1050 return results
1051
estadee17314a02017-01-12 16:22:161052def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1053 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1054 errors = []
1055 for f in input_api.AffectedFiles():
1056 for line_num, line in f.ChangedContents():
1057 if pattern.search(line):
1058 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1059
1060 results = []
1061 if errors:
1062 results.append(output_api.PresubmitPromptWarning(
1063 'Found Google support URL addressed by answer number. Please replace with '
1064 'a p= identifier instead. See crbug.com/679462\n', errors))
1065 return results
1066
[email protected]70ca77752012-11-20 03:45:031067
[email protected]06e6d0ff2012-12-11 01:36:441068def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1069 def FilterFile(affected_file):
1070 """Filter function for use with input_api.AffectedSourceFiles,
1071 below. This filters out everything except non-test files from
1072 top-level directories that generally speaking should not hard-code
1073 service URLs (e.g. src/android_webview/, src/content/ and others).
1074 """
1075 return input_api.FilterSourceFile(
1076 affected_file,
[email protected]78bb39d62012-12-11 15:11:561077 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441078 black_list=(_EXCLUDED_PATHS +
1079 _TEST_CODE_EXCLUDED_PATHS +
1080 input_api.DEFAULT_BLACK_LIST))
1081
reillyi38965732015-11-16 18:27:331082 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1083 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461084 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1085 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441086 problems = [] # items are (filename, line_number, line)
1087 for f in input_api.AffectedSourceFiles(FilterFile):
1088 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461089 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441090 problems.append((f.LocalPath(), line_num, line))
1091
1092 if problems:
[email protected]f7051d52013-04-02 18:31:421093 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441094 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581095 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441096 [' %s:%d: %s' % (
1097 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031098 else:
1099 return []
[email protected]06e6d0ff2012-12-11 01:36:441100
1101
[email protected]d2530012013-01-25 16:39:271102def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1103 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311104 The native_client_sdk directory is excluded because it has auto-generated PNG
1105 files for documentation.
[email protected]d2530012013-01-25 16:39:271106 """
[email protected]d2530012013-01-25 16:39:271107 errors = []
binji0dcdf342014-12-12 18:32:311108 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1109 black_list = (r'^native_client_sdk[\\\/]',)
1110 file_filter = lambda f: input_api.FilterSourceFile(
1111 f, white_list=white_list, black_list=black_list)
1112 for f in input_api.AffectedFiles(include_deletes=False,
1113 file_filter=file_filter):
1114 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271115
1116 results = []
1117 if errors:
1118 results.append(output_api.PresubmitError(
1119 'The name of PNG files should not have abbreviations. \n'
1120 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1121 'Contact [email protected] if you have questions.', errors))
1122 return results
1123
1124
Daniel Cheng4dcdb6b2017-04-13 08:30:171125def _ExtractAddRulesFromParsedDeps(parsed_deps):
1126 """Extract the rules that add dependencies from a parsed DEPS file.
1127
1128 Args:
1129 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1130 add_rules = set()
1131 add_rules.update([
1132 rule[1:] for rule in parsed_deps.get('include_rules', [])
1133 if rule.startswith('+') or rule.startswith('!')
1134 ])
1135 for specific_file, rules in parsed_deps.get('specific_include_rules',
1136 {}).iteritems():
1137 add_rules.update([
1138 rule[1:] for rule in rules
1139 if rule.startswith('+') or rule.startswith('!')
1140 ])
1141 return add_rules
1142
1143
1144def _ParseDeps(contents):
1145 """Simple helper for parsing DEPS files."""
1146 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171147 class _VarImpl:
1148
1149 def __init__(self, local_scope):
1150 self._local_scope = local_scope
1151
1152 def Lookup(self, var_name):
1153 """Implements the Var syntax."""
1154 try:
1155 return self._local_scope['vars'][var_name]
1156 except KeyError:
1157 raise Exception('Var is not defined: %s' % var_name)
1158
1159 local_scope = {}
1160 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171161 'Var': _VarImpl(local_scope).Lookup,
1162 }
1163 exec contents in global_scope, local_scope
1164 return local_scope
1165
1166
1167def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081168 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411169 a set of DEPS entries that we should look up.
1170
1171 For a directory (rather than a specific filename) we fake a path to
1172 a specific filename by adding /DEPS. This is chosen as a file that
1173 will seldom or never be subject to per-file include_rules.
1174 """
[email protected]2b438d62013-11-14 17:54:141175 # We ignore deps entries on auto-generated directories.
1176 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081177
Daniel Cheng4dcdb6b2017-04-13 08:30:171178 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1179 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1180
1181 added_deps = new_deps.difference(old_deps)
1182
[email protected]2b438d62013-11-14 17:54:141183 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171184 for added_dep in added_deps:
1185 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1186 continue
1187 # Assume that a rule that ends in .h is a rule for a specific file.
1188 if added_dep.endswith('.h'):
1189 results.add(added_dep)
1190 else:
1191 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081192 return results
1193
1194
[email protected]e871964c2013-05-13 14:14:551195def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1196 """When a dependency prefixed with + is added to a DEPS file, we
1197 want to make sure that the change is reviewed by an OWNER of the
1198 target file or directory, to avoid layering violations from being
1199 introduced. This check verifies that this happens.
1200 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171201 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241202
1203 file_filter = lambda f: not input_api.re.match(
1204 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1205 for f in input_api.AffectedFiles(include_deletes=False,
1206 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551207 filename = input_api.os_path.basename(f.LocalPath())
1208 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171209 virtual_depended_on_files.update(_CalculateAddedDeps(
1210 input_api.os_path,
1211 '\n'.join(f.OldContents()),
1212 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551213
[email protected]e871964c2013-05-13 14:14:551214 if not virtual_depended_on_files:
1215 return []
1216
1217 if input_api.is_committing:
1218 if input_api.tbr:
1219 return [output_api.PresubmitNotifyResult(
1220 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271221 if input_api.dry_run:
1222 return [output_api.PresubmitNotifyResult(
1223 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551224 if not input_api.change.issue:
1225 return [output_api.PresubmitError(
1226 "DEPS approval by OWNERS check failed: this change has "
1227 "no Rietveld issue number, so we can't check it for approvals.")]
1228 output = output_api.PresubmitError
1229 else:
1230 output = output_api.PresubmitNotifyResult
1231
1232 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501233 owner_email, reviewers = (
1234 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1235 input_api,
1236 owners_db.email_regexp,
1237 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551238
1239 owner_email = owner_email or input_api.change.author_email
1240
[email protected]de4f7d22013-05-23 14:27:461241 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511242 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461243 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551244 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1245 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411246
1247 # We strip the /DEPS part that was added by
1248 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1249 # directory.
1250 def StripDeps(path):
1251 start_deps = path.rfind('/DEPS')
1252 if start_deps != -1:
1253 return path[:start_deps]
1254 else:
1255 return path
1256 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551257 for path in missing_files]
1258
1259 if unapproved_dependencies:
1260 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151261 output('You need LGTM from owners of depends-on paths in DEPS that were '
1262 'modified in this CL:\n %s' %
1263 '\n '.join(sorted(unapproved_dependencies)))]
1264 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1265 output_list.append(output(
1266 'Suggested missing target path OWNERS:\n %s' %
1267 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551268 return output_list
1269
1270 return []
1271
1272
[email protected]85218562013-11-22 07:41:401273def _CheckSpamLogging(input_api, output_api):
1274 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1275 black_list = (_EXCLUDED_PATHS +
1276 _TEST_CODE_EXCLUDED_PATHS +
1277 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501278 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191279 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481280 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461281 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121282 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1283 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581284 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161285 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031286 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151287 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1288 r"^chromecast[\\\/]",
1289 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481290 r"^components[\\\/]browser_watcher[\\\/]"
1291 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311292 r"^components[\\\/]html_viewer[\\\/]"
1293 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461294 # TODO(peter): Remove this exception. https://crbug.com/534537
1295 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1296 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251297 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1298 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241299 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111300 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151301 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111302 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521303 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501304 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361305 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311306 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131307 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001308 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441309 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451310 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021311 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351312 r"dump_file_system.cc$",
1313 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401314 source_file_filter = lambda x: input_api.FilterSourceFile(
1315 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1316
thomasanderson625d3932017-03-29 07:16:581317 log_info = set([])
1318 printf = set([])
[email protected]85218562013-11-22 07:41:401319
1320 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581321 for _, line in f.ChangedContents():
1322 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1323 log_info.add(f.LocalPath())
1324 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1325 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371326
thomasanderson625d3932017-03-29 07:16:581327 if input_api.re.search(r"\bprintf\(", line):
1328 printf.add(f.LocalPath())
1329 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1330 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401331
1332 if log_info:
1333 return [output_api.PresubmitError(
1334 'These files spam the console log with LOG(INFO):',
1335 items=log_info)]
1336 if printf:
1337 return [output_api.PresubmitError(
1338 'These files spam the console log with printf/fprintf:',
1339 items=printf)]
1340 return []
1341
1342
[email protected]49aa76a2013-12-04 06:59:161343def _CheckForAnonymousVariables(input_api, output_api):
1344 """These types are all expected to hold locks while in scope and
1345 so should never be anonymous (which causes them to be immediately
1346 destroyed)."""
1347 they_who_must_be_named = [
1348 'base::AutoLock',
1349 'base::AutoReset',
1350 'base::AutoUnlock',
1351 'SkAutoAlphaRestore',
1352 'SkAutoBitmapShaderInstall',
1353 'SkAutoBlitterChoose',
1354 'SkAutoBounderCommit',
1355 'SkAutoCallProc',
1356 'SkAutoCanvasRestore',
1357 'SkAutoCommentBlock',
1358 'SkAutoDescriptor',
1359 'SkAutoDisableDirectionCheck',
1360 'SkAutoDisableOvalCheck',
1361 'SkAutoFree',
1362 'SkAutoGlyphCache',
1363 'SkAutoHDC',
1364 'SkAutoLockColors',
1365 'SkAutoLockPixels',
1366 'SkAutoMalloc',
1367 'SkAutoMaskFreeImage',
1368 'SkAutoMutexAcquire',
1369 'SkAutoPathBoundsUpdate',
1370 'SkAutoPDFRelease',
1371 'SkAutoRasterClipValidate',
1372 'SkAutoRef',
1373 'SkAutoTime',
1374 'SkAutoTrace',
1375 'SkAutoUnref',
1376 ]
1377 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1378 # bad: base::AutoLock(lock.get());
1379 # not bad: base::AutoLock lock(lock.get());
1380 bad_pattern = input_api.re.compile(anonymous)
1381 # good: new base::AutoLock(lock.get())
1382 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1383 errors = []
1384
1385 for f in input_api.AffectedFiles():
1386 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1387 continue
1388 for linenum, line in f.ChangedContents():
1389 if bad_pattern.search(line) and not good_pattern.search(line):
1390 errors.append('%s:%d' % (f.LocalPath(), linenum))
1391
1392 if errors:
1393 return [output_api.PresubmitError(
1394 'These lines create anonymous variables that need to be named:',
1395 items=errors)]
1396 return []
1397
1398
[email protected]5fe0f8742013-11-29 01:04:591399def _CheckCygwinShell(input_api, output_api):
1400 source_file_filter = lambda x: input_api.FilterSourceFile(
1401 x, white_list=(r'.+\.(gyp|gypi)$',))
1402 cygwin_shell = []
1403
1404 for f in input_api.AffectedSourceFiles(source_file_filter):
1405 for linenum, line in f.ChangedContents():
1406 if 'msvs_cygwin_shell' in line:
1407 cygwin_shell.append(f.LocalPath())
1408 break
1409
1410 if cygwin_shell:
1411 return [output_api.PresubmitError(
1412 'These files should not use msvs_cygwin_shell (the default is 0):',
1413 items=cygwin_shell)]
1414 return []
1415
[email protected]85218562013-11-22 07:41:401416
[email protected]999261d2014-03-03 20:08:081417def _CheckUserActionUpdate(input_api, output_api):
1418 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521419 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081420 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521421 # If actions.xml is already included in the changelist, the PRESUBMIT
1422 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081423 return []
1424
[email protected]999261d2014-03-03 20:08:081425 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1426 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521427 current_actions = None
[email protected]999261d2014-03-03 20:08:081428 for f in input_api.AffectedFiles(file_filter=file_filter):
1429 for line_num, line in f.ChangedContents():
1430 match = input_api.re.search(action_re, line)
1431 if match:
[email protected]2f92dec2014-03-07 19:21:521432 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1433 # loaded only once.
1434 if not current_actions:
1435 with open('tools/metrics/actions/actions.xml') as actions_f:
1436 current_actions = actions_f.read()
1437 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081438 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521439 action = 'name="{0}"'.format(action_name)
1440 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081441 return [output_api.PresubmitPromptWarning(
1442 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521443 'tools/metrics/actions/actions.xml. Please run '
1444 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081445 % (f.LocalPath(), line_num, action_name))]
1446 return []
1447
1448
[email protected]99171a92014-06-03 08:44:471449def _GetJSONParseError(input_api, filename, eat_comments=True):
1450 try:
1451 contents = input_api.ReadFile(filename)
1452 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131453 import sys
1454 original_sys_path = sys.path
1455 try:
1456 sys.path = sys.path + [input_api.os_path.join(
1457 input_api.PresubmitLocalPath(),
1458 'tools', 'json_comment_eater')]
1459 import json_comment_eater
1460 finally:
1461 sys.path = original_sys_path
1462 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471463
1464 input_api.json.loads(contents)
1465 except ValueError as e:
1466 return e
1467 return None
1468
1469
1470def _GetIDLParseError(input_api, filename):
1471 try:
1472 contents = input_api.ReadFile(filename)
1473 idl_schema = input_api.os_path.join(
1474 input_api.PresubmitLocalPath(),
1475 'tools', 'json_schema_compiler', 'idl_schema.py')
1476 process = input_api.subprocess.Popen(
1477 [input_api.python_executable, idl_schema],
1478 stdin=input_api.subprocess.PIPE,
1479 stdout=input_api.subprocess.PIPE,
1480 stderr=input_api.subprocess.PIPE,
1481 universal_newlines=True)
1482 (_, error) = process.communicate(input=contents)
1483 return error or None
1484 except ValueError as e:
1485 return e
1486
1487
1488def _CheckParseErrors(input_api, output_api):
1489 """Check that IDL and JSON files do not contain syntax errors."""
1490 actions = {
1491 '.idl': _GetIDLParseError,
1492 '.json': _GetJSONParseError,
1493 }
1494 # These paths contain test data and other known invalid JSON files.
1495 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491496 r'test[\\\/]data[\\\/]',
1497 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471498 ]
1499 # Most JSON files are preprocessed and support comments, but these do not.
1500 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491501 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471502 ]
1503 # Only run IDL checker on files in these directories.
1504 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491505 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1506 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471507 ]
1508
1509 def get_action(affected_file):
1510 filename = affected_file.LocalPath()
1511 return actions.get(input_api.os_path.splitext(filename)[1])
1512
1513 def MatchesFile(patterns, path):
1514 for pattern in patterns:
1515 if input_api.re.search(pattern, path):
1516 return True
1517 return False
1518
1519 def FilterFile(affected_file):
1520 action = get_action(affected_file)
1521 if not action:
1522 return False
1523 path = affected_file.LocalPath()
1524
1525 if MatchesFile(excluded_patterns, path):
1526 return False
1527
1528 if (action == _GetIDLParseError and
1529 not MatchesFile(idl_included_patterns, path)):
1530 return False
1531 return True
1532
1533 results = []
1534 for affected_file in input_api.AffectedFiles(
1535 file_filter=FilterFile, include_deletes=False):
1536 action = get_action(affected_file)
1537 kwargs = {}
1538 if (action == _GetJSONParseError and
1539 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1540 kwargs['eat_comments'] = False
1541 parse_error = action(input_api,
1542 affected_file.AbsoluteLocalPath(),
1543 **kwargs)
1544 if parse_error:
1545 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1546 (affected_file.LocalPath(), parse_error)))
1547 return results
1548
1549
[email protected]760deea2013-12-10 19:33:491550def _CheckJavaStyle(input_api, output_api):
1551 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471552 import sys
[email protected]760deea2013-12-10 19:33:491553 original_sys_path = sys.path
1554 try:
1555 sys.path = sys.path + [input_api.os_path.join(
1556 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1557 import checkstyle
1558 finally:
1559 # Restore sys.path to what it was before.
1560 sys.path = original_sys_path
1561
1562 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091563 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511564 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491565
1566
dchenge07de812016-06-20 19:27:171567def _CheckIpcOwners(input_api, output_api):
1568 """Checks that affected files involving IPC have an IPC OWNERS rule.
1569
1570 Whether or not a file affects IPC is determined by a simple whitelist of
1571 filename patterns."""
1572 file_patterns = [
palmerb19a0932017-01-24 04:00:311573 # Legacy IPC:
dchenge07de812016-06-20 19:27:171574 '*_messages.cc',
1575 '*_messages*.h',
1576 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311577 # Mojo IPC:
dchenge07de812016-06-20 19:27:171578 '*.mojom',
1579 '*_struct_traits*.*',
1580 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311581 '*.typemap',
1582 # Android native IPC:
1583 '*.aidl',
1584 # Blink uses a different file naming convention:
1585 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171586 '*StructTraits*.*',
1587 '*TypeConverter*.*',
1588 ]
1589
scottmg7a6ed5ba2016-11-04 18:22:041590 # These third_party directories do not contain IPCs, but contain files
1591 # matching the above patterns, which trigger false positives.
1592 exclude_paths = [
1593 'third_party/crashpad/*',
1594 ]
1595
dchenge07de812016-06-20 19:27:171596 # Dictionary mapping an OWNERS file path to Patterns.
1597 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1598 # rules ) to a PatternEntry.
1599 # PatternEntry is a dictionary with two keys:
1600 # - 'files': the files that are matched by this pattern
1601 # - 'rules': the per-file rules needed for this pattern
1602 # For example, if we expect OWNERS file to contain rules for *.mojom and
1603 # *_struct_traits*.*, Patterns might look like this:
1604 # {
1605 # '*.mojom': {
1606 # 'files': ...,
1607 # 'rules': [
1608 # 'per-file *.mojom=set noparent',
1609 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1610 # ],
1611 # },
1612 # '*_struct_traits*.*': {
1613 # 'files': ...,
1614 # 'rules': [
1615 # 'per-file *_struct_traits*.*=set noparent',
1616 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1617 # ],
1618 # },
1619 # }
1620 to_check = {}
1621
1622 # Iterate through the affected files to see what we actually need to check
1623 # for. We should only nag patch authors about per-file rules if a file in that
1624 # directory would match that pattern. If a directory only contains *.mojom
1625 # files and no *_messages*.h files, we should only nag about rules for
1626 # *.mojom files.
rockot51249332016-06-23 16:32:251627 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171628 for pattern in file_patterns:
1629 if input_api.fnmatch.fnmatch(
1630 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041631 skip = False
1632 for exclude in exclude_paths:
1633 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1634 skip = True
1635 break
1636 if skip:
1637 continue
dchenge07de812016-06-20 19:27:171638 owners_file = input_api.os_path.join(
1639 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1640 if owners_file not in to_check:
1641 to_check[owners_file] = {}
1642 if pattern not in to_check[owners_file]:
1643 to_check[owners_file][pattern] = {
1644 'files': [],
1645 'rules': [
1646 'per-file %s=set noparent' % pattern,
1647 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1648 ]
1649 }
1650 to_check[owners_file][pattern]['files'].append(f)
1651 break
1652
1653 # Now go through the OWNERS files we collected, filtering out rules that are
1654 # already present in that OWNERS file.
1655 for owners_file, patterns in to_check.iteritems():
1656 try:
1657 with file(owners_file) as f:
1658 lines = set(f.read().splitlines())
1659 for entry in patterns.itervalues():
1660 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1661 ]
1662 except IOError:
1663 # No OWNERS file, so all the rules are definitely missing.
1664 continue
1665
1666 # All the remaining lines weren't found in OWNERS files, so emit an error.
1667 errors = []
1668 for owners_file, patterns in to_check.iteritems():
1669 missing_lines = []
1670 files = []
1671 for pattern, entry in patterns.iteritems():
1672 missing_lines.extend(entry['rules'])
1673 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1674 if missing_lines:
1675 errors.append(
1676 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1677 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1678
1679 results = []
1680 if errors:
vabrf5ce3bf92016-07-11 14:52:411681 if input_api.is_committing:
1682 output = output_api.PresubmitError
1683 else:
1684 output = output_api.PresubmitPromptWarning
1685 results.append(output(
dchenge07de812016-06-20 19:27:171686 'Found changes to IPC files without a security OWNER!',
1687 long_text='\n\n'.join(errors)))
1688
1689 return results
1690
1691
jbriance9e12f162016-11-25 07:57:501692def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311693 """Checks that added or removed lines in non third party affected
1694 header files do not lead to new useless class or struct forward
1695 declaration.
jbriance9e12f162016-11-25 07:57:501696 """
1697 results = []
1698 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1699 input_api.re.MULTILINE)
1700 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1701 input_api.re.MULTILINE)
1702 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311703 if (f.LocalPath().startswith('third_party') and
1704 not f.LocalPath().startswith('third_party/WebKit') and
1705 not f.LocalPath().startswith('third_party\\WebKit')):
1706 continue
1707
jbriance9e12f162016-11-25 07:57:501708 if not f.LocalPath().endswith('.h'):
1709 continue
1710
1711 contents = input_api.ReadFile(f)
1712 fwd_decls = input_api.re.findall(class_pattern, contents)
1713 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1714
1715 useless_fwd_decls = []
1716 for decl in fwd_decls:
1717 count = sum(1 for _ in input_api.re.finditer(
1718 r'\b%s\b' % input_api.re.escape(decl), contents))
1719 if count == 1:
1720 useless_fwd_decls.append(decl)
1721
1722 if not useless_fwd_decls:
1723 continue
1724
1725 for line in f.GenerateScmDiff().splitlines():
1726 if (line.startswith('-') and not line.startswith('--') or
1727 line.startswith('+') and not line.startswith('++')):
1728 for decl in useless_fwd_decls:
1729 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1730 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241731 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501732 (f.LocalPath(), decl)))
1733 useless_fwd_decls.remove(decl)
1734
1735 return results
1736
1737
dskiba88634f4e2015-08-14 23:03:291738def _CheckAndroidToastUsage(input_api, output_api):
1739 """Checks that code uses org.chromium.ui.widget.Toast instead of
1740 android.widget.Toast (Chromium Toast doesn't force hardware
1741 acceleration on low-end devices, saving memory).
1742 """
1743 toast_import_pattern = input_api.re.compile(
1744 r'^import android\.widget\.Toast;$')
1745
1746 errors = []
1747
1748 sources = lambda affected_file: input_api.FilterSourceFile(
1749 affected_file,
1750 black_list=(_EXCLUDED_PATHS +
1751 _TEST_CODE_EXCLUDED_PATHS +
1752 input_api.DEFAULT_BLACK_LIST +
1753 (r'^chromecast[\\\/].*',
1754 r'^remoting[\\\/].*')),
1755 white_list=(r'.*\.java$',))
1756
1757 for f in input_api.AffectedSourceFiles(sources):
1758 for line_num, line in f.ChangedContents():
1759 if toast_import_pattern.search(line):
1760 errors.append("%s:%d" % (f.LocalPath(), line_num))
1761
1762 results = []
1763
1764 if errors:
1765 results.append(output_api.PresubmitError(
1766 'android.widget.Toast usage is detected. Android toasts use hardware'
1767 ' acceleration, and can be\ncostly on low-end devices. Please use'
1768 ' org.chromium.ui.widget.Toast instead.\n'
1769 'Contact [email protected] if you have any questions.',
1770 errors))
1771
1772 return results
1773
1774
dgnaa68d5e2015-06-10 10:08:221775def _CheckAndroidCrLogUsage(input_api, output_api):
1776 """Checks that new logs using org.chromium.base.Log:
1777 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511778 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221779 """
pkotwicza1dd0b002016-05-16 14:41:041780
torne89540622017-03-24 19:41:301781 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041782 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301783 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041784 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301785 # WebView license viewer code cannot depend on //base; used in stub APK.
1786 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1787 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041788 ]
1789
dgnaa68d5e2015-06-10 10:08:221790 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121791 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1792 class_in_base_pattern = input_api.re.compile(
1793 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1794 has_some_log_import_pattern = input_api.re.compile(
1795 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221796 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121797 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221798 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511799 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221800 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221801
Vincent Scheib16d7b272015-09-15 18:09:071802 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221803 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041804 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1805 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121806
dgnaa68d5e2015-06-10 10:08:221807 tag_decl_errors = []
1808 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121809 tag_errors = []
dgn38736db2015-09-18 19:20:511810 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121811 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221812
1813 for f in input_api.AffectedSourceFiles(sources):
1814 file_content = input_api.ReadFile(f)
1815 has_modified_logs = False
1816
1817 # Per line checks
dgn87d9fb62015-06-12 09:15:121818 if (cr_log_import_pattern.search(file_content) or
1819 (class_in_base_pattern.search(file_content) and
1820 not has_some_log_import_pattern.search(file_content))):
1821 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221822 for line_num, line in f.ChangedContents():
1823
1824 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121825 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221826 if match:
1827 has_modified_logs = True
1828
1829 # Make sure it uses "TAG"
1830 if not match.group('tag') == 'TAG':
1831 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121832 else:
1833 # Report non cr Log function calls in changed lines
1834 for line_num, line in f.ChangedContents():
1835 if log_call_pattern.search(line):
1836 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221837
1838 # Per file checks
1839 if has_modified_logs:
1840 # Make sure the tag is using the "cr" prefix and is not too long
1841 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511842 tag_name = match.group('name') if match else None
1843 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221844 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511845 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221846 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511847 elif '.' in tag_name:
1848 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221849
1850 results = []
1851 if tag_decl_errors:
1852 results.append(output_api.PresubmitPromptWarning(
1853 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511854 '"private static final String TAG = "<package tag>".\n'
1855 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221856 tag_decl_errors))
1857
1858 if tag_length_errors:
1859 results.append(output_api.PresubmitError(
1860 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511861 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221862 tag_length_errors))
1863
1864 if tag_errors:
1865 results.append(output_api.PresubmitPromptWarning(
1866 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1867 tag_errors))
1868
dgn87d9fb62015-06-12 09:15:121869 if util_log_errors:
dgn4401aa52015-04-29 16:26:171870 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121871 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1872 util_log_errors))
1873
dgn38736db2015-09-18 19:20:511874 if tag_with_dot_errors:
1875 results.append(output_api.PresubmitPromptWarning(
1876 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1877 tag_with_dot_errors))
1878
dgn4401aa52015-04-29 16:26:171879 return results
1880
1881
yolandyan45001472016-12-21 21:12:421882def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1883 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1884 deprecated_annotation_import_pattern = input_api.re.compile(
1885 r'^import android\.test\.suitebuilder\.annotation\..*;',
1886 input_api.re.MULTILINE)
1887 sources = lambda x: input_api.FilterSourceFile(
1888 x, white_list=(r'.*\.java$',), black_list=None)
1889 errors = []
1890 for f in input_api.AffectedFiles(sources):
1891 for line_num, line in f.ChangedContents():
1892 if deprecated_annotation_import_pattern.search(line):
1893 errors.append("%s:%d" % (f.LocalPath(), line_num))
1894
1895 results = []
1896 if errors:
1897 results.append(output_api.PresubmitError(
1898 'Annotations in android.test.suitebuilder.annotation have been'
1899 ' deprecated since API level 24. Please use android.support.test.filters'
1900 ' from //third_party/android_support_test_runner:runner_java instead.'
1901 ' Contact [email protected] if you have any questions.', errors))
1902 return results
1903
1904
agrieve7b6479d82015-10-07 14:24:221905def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1906 """Checks if MDPI assets are placed in a correct directory."""
1907 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1908 ('/res/drawable/' in f.LocalPath() or
1909 '/res/drawable-ldrtl/' in f.LocalPath()))
1910 errors = []
1911 for f in input_api.AffectedFiles(include_deletes=False,
1912 file_filter=file_filter):
1913 errors.append(' %s' % f.LocalPath())
1914
1915 results = []
1916 if errors:
1917 results.append(output_api.PresubmitError(
1918 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1919 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1920 '/res/drawable-ldrtl/.\n'
1921 'Contact [email protected] if you have questions.', errors))
1922 return results
1923
1924
agrievef32bcc72016-04-04 14:57:401925class PydepsChecker(object):
1926 def __init__(self, input_api, pydeps_files):
1927 self._file_cache = {}
1928 self._input_api = input_api
1929 self._pydeps_files = pydeps_files
1930
1931 def _LoadFile(self, path):
1932 """Returns the list of paths within a .pydeps file relative to //."""
1933 if path not in self._file_cache:
1934 with open(path) as f:
1935 self._file_cache[path] = f.read()
1936 return self._file_cache[path]
1937
1938 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1939 """Returns an interable of paths within the .pydep, relativized to //."""
1940 os_path = self._input_api.os_path
1941 pydeps_dir = os_path.dirname(pydeps_path)
1942 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1943 if not l.startswith('*'))
1944 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1945
1946 def _CreateFilesToPydepsMap(self):
1947 """Returns a map of local_path -> list_of_pydeps."""
1948 ret = {}
1949 for pydep_local_path in self._pydeps_files:
1950 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1951 ret.setdefault(path, []).append(pydep_local_path)
1952 return ret
1953
1954 def ComputeAffectedPydeps(self):
1955 """Returns an iterable of .pydeps files that might need regenerating."""
1956 affected_pydeps = set()
1957 file_to_pydeps_map = None
1958 for f in self._input_api.AffectedFiles(include_deletes=True):
1959 local_path = f.LocalPath()
1960 if local_path == 'DEPS':
1961 return self._pydeps_files
1962 elif local_path.endswith('.pydeps'):
1963 if local_path in self._pydeps_files:
1964 affected_pydeps.add(local_path)
1965 elif local_path.endswith('.py'):
1966 if file_to_pydeps_map is None:
1967 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1968 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1969 return affected_pydeps
1970
1971 def DetermineIfStale(self, pydeps_path):
1972 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411973 import difflib
agrievef32bcc72016-04-04 14:57:401974 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1975 cmd = old_pydeps_data[1][1:].strip()
1976 new_pydeps_data = self._input_api.subprocess.check_output(
1977 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411978 old_contents = old_pydeps_data[2:]
1979 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401980 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411981 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401982
1983
1984def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1985 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001986 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281987 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1988 # Mac, so skip it on other platforms.
1989 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001990 return []
agrievef32bcc72016-04-04 14:57:401991 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1992 is_android = input_api.os_path.exists('third_party/android_tools')
1993 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1994 results = []
1995 # First, check for new / deleted .pydeps.
1996 for f in input_api.AffectedFiles(include_deletes=True):
1997 if f.LocalPath().endswith('.pydeps'):
1998 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1999 results.append(output_api.PresubmitError(
2000 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2001 'remove %s' % f.LocalPath()))
2002 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2003 results.append(output_api.PresubmitError(
2004 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2005 'include %s' % f.LocalPath()))
2006
2007 if results:
2008 return results
2009
2010 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2011
2012 for pydep_path in checker.ComputeAffectedPydeps():
2013 try:
phajdan.jr0d9878552016-11-04 10:49:412014 result = checker.DetermineIfStale(pydep_path)
2015 if result:
2016 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402017 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412018 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2019 'To regenerate, run:\n\n %s' %
2020 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402021 except input_api.subprocess.CalledProcessError as error:
2022 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2023 long_text=error.output)]
2024
2025 return results
2026
2027
glidere61efad2015-02-18 17:39:432028def _CheckSingletonInHeaders(input_api, output_api):
2029 """Checks to make sure no header files have |Singleton<|."""
2030 def FileFilter(affected_file):
2031 # It's ok for base/memory/singleton.h to have |Singleton<|.
2032 black_list = (_EXCLUDED_PATHS +
2033 input_api.DEFAULT_BLACK_LIST +
2034 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
2035 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2036
sergeyu34d21222015-09-16 00:11:442037 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432038 files = []
2039 for f in input_api.AffectedSourceFiles(FileFilter):
2040 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2041 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2042 contents = input_api.ReadFile(f)
2043 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242044 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432045 pattern.search(line)):
2046 files.append(f)
2047 break
2048
2049 if files:
yolandyandaabc6d2016-04-18 18:29:392050 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442051 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432052 'Please move them to an appropriate source file so that the ' +
2053 'template gets instantiated in a single compilation unit.',
2054 files) ]
2055 return []
2056
2057
[email protected]fd20b902014-05-09 02:14:532058_DEPRECATED_CSS = [
2059 # Values
2060 ( "-webkit-box", "flex" ),
2061 ( "-webkit-inline-box", "inline-flex" ),
2062 ( "-webkit-flex", "flex" ),
2063 ( "-webkit-inline-flex", "inline-flex" ),
2064 ( "-webkit-min-content", "min-content" ),
2065 ( "-webkit-max-content", "max-content" ),
2066
2067 # Properties
2068 ( "-webkit-background-clip", "background-clip" ),
2069 ( "-webkit-background-origin", "background-origin" ),
2070 ( "-webkit-background-size", "background-size" ),
2071 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442072 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532073
2074 # Functions
2075 ( "-webkit-gradient", "gradient" ),
2076 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2077 ( "-webkit-linear-gradient", "linear-gradient" ),
2078 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2079 ( "-webkit-radial-gradient", "radial-gradient" ),
2080 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2081]
2082
dbeam1ec68ac2016-12-15 05:22:242083def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532084 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252085 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342086 documentation and iOS CSS for dom distiller
2087 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252088 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532089 results = []
dbeam070cfe62014-10-22 06:44:022090 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252091 black_list = (_EXCLUDED_PATHS +
2092 _TEST_CODE_EXCLUDED_PATHS +
2093 input_api.DEFAULT_BLACK_LIST +
2094 (r"^chrome/common/extensions/docs",
2095 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342096 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052097 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442098 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252099 r"^native_client_sdk"))
2100 file_filter = lambda f: input_api.FilterSourceFile(
2101 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532102 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2103 for line_num, line in fpath.ChangedContents():
2104 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022105 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532106 results.append(output_api.PresubmitError(
2107 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2108 (fpath.LocalPath(), line_num, deprecated_value, value)))
2109 return results
2110
mohan.reddyf21db962014-10-16 12:26:472111
dbeam070cfe62014-10-22 06:44:022112_DEPRECATED_JS = [
2113 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2114 ( "__defineGetter__", "Object.defineProperty" ),
2115 ( "__defineSetter__", "Object.defineProperty" ),
2116]
2117
dbeam1ec68ac2016-12-15 05:22:242118def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022119 """Make sure that we don't use deprecated JS in Chrome code."""
2120 results = []
2121 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2122 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2123 input_api.DEFAULT_BLACK_LIST)
2124 file_filter = lambda f: input_api.FilterSourceFile(
2125 f, white_list=file_inclusion_pattern, black_list=black_list)
2126 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2127 for lnum, line in fpath.ChangedContents():
2128 for (deprecated, replacement) in _DEPRECATED_JS:
2129 if deprecated in line:
2130 results.append(output_api.PresubmitError(
2131 "%s:%d: Use of deprecated JS %s, use %s instead" %
2132 (fpath.LocalPath(), lnum, deprecated, replacement)))
2133 return results
2134
2135
dbeam1ec68ac2016-12-15 05:22:242136def _CheckForRiskyJsFeatures(input_api, output_api):
2137 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2138 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2139
2140 arrow_lines = []
2141 for f in input_api.AffectedFiles(file_filter=file_filter):
2142 for lnum, line in f.ChangedContents():
2143 if ' => ' in line:
2144 arrow_lines.append((f.LocalPath(), lnum))
2145
2146 if not arrow_lines:
2147 return []
2148
2149 return [output_api.PresubmitPromptWarning("""
2150Use of => operator detected in:
2151%s
2152Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2153https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2154""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2155
2156
rlanday6802cf632017-05-30 17:48:362157def _CheckForRelativeIncludes(input_api, output_api):
2158 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2159 import sys
2160 original_sys_path = sys.path
2161 try:
2162 sys.path = sys.path + [input_api.os_path.join(
2163 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2164 from cpp_checker import CppChecker
2165 finally:
2166 # Restore sys.path to what it was before.
2167 sys.path = original_sys_path
2168
2169 bad_files = {}
2170 for f in input_api.AffectedFiles(include_deletes=False):
2171 if (f.LocalPath().startswith('third_party') and
2172 not f.LocalPath().startswith('third_party/WebKit') and
2173 not f.LocalPath().startswith('third_party\\WebKit')):
2174 continue
2175
2176 if not CppChecker.IsCppFile(f.LocalPath()):
2177 continue
2178
2179 relative_includes = [line for line_num, line in f.ChangedContents()
2180 if "#include" in line and "../" in line]
2181 if not relative_includes:
2182 continue
2183 bad_files[f.LocalPath()] = relative_includes
2184
2185 if not bad_files:
2186 return []
2187
2188 error_descriptions = []
2189 for file_path, bad_lines in bad_files.iteritems():
2190 error_description = file_path
2191 for line in bad_lines:
2192 error_description += '\n ' + line
2193 error_descriptions.append(error_description)
2194
2195 results = []
2196 results.append(output_api.PresubmitError(
2197 'You added one or more relative #include paths (including "../").\n'
2198 'These shouldn\'t be used because they can be used to include headers\n'
2199 'from code that\'s not correctly specified as a dependency in the\n'
2200 'relevant BUILD.gn file(s).',
2201 error_descriptions))
2202
2203 return results
2204
dgnaa68d5e2015-06-10 10:08:222205def _AndroidSpecificOnUploadChecks(input_api, output_api):
2206 """Groups checks that target android code."""
2207 results = []
dgnaa68d5e2015-06-10 10:08:222208 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222209 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292210 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422211 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222212 return results
2213
2214
[email protected]22c9bd72011-03-27 16:47:392215def _CommonChecks(input_api, output_api):
2216 """Checks common to both upload and commit."""
2217 results = []
2218 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382219 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542220 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582221 results.extend(
2222 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192223 results.extend(
[email protected]760deea2013-12-10 19:33:492224 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542225 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182226 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522227 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222228 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442229 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592230 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062231 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122232 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182233 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222234 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302235 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492236 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272237 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032238 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492239 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442240 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272241 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542242 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442243 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392244 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552245 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042246 results.extend(
2247 input_api.canned_checks.CheckChangeHasNoTabs(
2248 input_api,
2249 output_api,
2250 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402251 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162252 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592253 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082254 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242255 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2256 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472257 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042258 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232259 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432260 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402261 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152262 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172263 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502264 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242265 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362266 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242267
2268 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2269 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2270 input_api, output_api,
2271 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382272 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392273 return results
[email protected]1f7b4172010-01-28 01:17:342274
[email protected]b337cb5b2011-01-23 21:24:052275
[email protected]b8079ae4a2012-12-05 19:56:492276def _CheckPatchFiles(input_api, output_api):
2277 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2278 if f.LocalPath().endswith(('.orig', '.rej'))]
2279 if problems:
2280 return [output_api.PresubmitError(
2281 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032282 else:
2283 return []
[email protected]b8079ae4a2012-12-05 19:56:492284
2285
[email protected]b00342e7f2013-03-26 16:21:542286def _DidYouMeanOSMacro(bad_macro):
2287 try:
2288 return {'A': 'OS_ANDROID',
2289 'B': 'OS_BSD',
2290 'C': 'OS_CHROMEOS',
2291 'F': 'OS_FREEBSD',
2292 'L': 'OS_LINUX',
2293 'M': 'OS_MACOSX',
2294 'N': 'OS_NACL',
2295 'O': 'OS_OPENBSD',
2296 'P': 'OS_POSIX',
2297 'S': 'OS_SOLARIS',
2298 'W': 'OS_WIN'}[bad_macro[3].upper()]
2299 except KeyError:
2300 return ''
2301
2302
2303def _CheckForInvalidOSMacrosInFile(input_api, f):
2304 """Check for sensible looking, totally invalid OS macros."""
2305 preprocessor_statement = input_api.re.compile(r'^\s*#')
2306 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2307 results = []
2308 for lnum, line in f.ChangedContents():
2309 if preprocessor_statement.search(line):
2310 for match in os_macro.finditer(line):
2311 if not match.group(1) in _VALID_OS_MACROS:
2312 good = _DidYouMeanOSMacro(match.group(1))
2313 did_you_mean = ' (did you mean %s?)' % good if good else ''
2314 results.append(' %s:%d %s%s' % (f.LocalPath(),
2315 lnum,
2316 match.group(1),
2317 did_you_mean))
2318 return results
2319
2320
2321def _CheckForInvalidOSMacros(input_api, output_api):
2322 """Check all affected files for invalid OS macros."""
2323 bad_macros = []
2324 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472325 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542326 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2327
2328 if not bad_macros:
2329 return []
2330
2331 return [output_api.PresubmitError(
2332 'Possibly invalid OS macro[s] found. Please fix your code\n'
2333 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2334
lliabraa35bab3932014-10-01 12:16:442335
2336def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2337 """Check all affected files for invalid "if defined" macros."""
2338 ALWAYS_DEFINED_MACROS = (
2339 "TARGET_CPU_PPC",
2340 "TARGET_CPU_PPC64",
2341 "TARGET_CPU_68K",
2342 "TARGET_CPU_X86",
2343 "TARGET_CPU_ARM",
2344 "TARGET_CPU_MIPS",
2345 "TARGET_CPU_SPARC",
2346 "TARGET_CPU_ALPHA",
2347 "TARGET_IPHONE_SIMULATOR",
2348 "TARGET_OS_EMBEDDED",
2349 "TARGET_OS_IPHONE",
2350 "TARGET_OS_MAC",
2351 "TARGET_OS_UNIX",
2352 "TARGET_OS_WIN32",
2353 )
2354 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2355 results = []
2356 for lnum, line in f.ChangedContents():
2357 for match in ifdef_macro.finditer(line):
2358 if match.group(1) in ALWAYS_DEFINED_MACROS:
2359 always_defined = ' %s is always defined. ' % match.group(1)
2360 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2361 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2362 lnum,
2363 always_defined,
2364 did_you_mean))
2365 return results
2366
2367
2368def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2369 """Check all affected files for invalid "if defined" macros."""
2370 bad_macros = []
2371 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212372 if f.LocalPath().startswith('third_party/sqlite/'):
2373 continue
lliabraa35bab3932014-10-01 12:16:442374 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2375 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2376
2377 if not bad_macros:
2378 return []
2379
2380 return [output_api.PresubmitError(
2381 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2382 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2383 bad_macros)]
2384
2385
mlamouria82272622014-09-16 18:45:042386def _CheckForIPCRules(input_api, output_api):
2387 """Check for same IPC rules described in
2388 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2389 """
2390 base_pattern = r'IPC_ENUM_TRAITS\('
2391 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2392 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2393
2394 problems = []
2395 for f in input_api.AffectedSourceFiles(None):
2396 local_path = f.LocalPath()
2397 if not local_path.endswith('.h'):
2398 continue
2399 for line_number, line in f.ChangedContents():
2400 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2401 problems.append(
2402 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2403
2404 if problems:
2405 return [output_api.PresubmitPromptWarning(
2406 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2407 else:
2408 return []
2409
[email protected]b00342e7f2013-03-26 16:21:542410
mostynbb639aca52015-01-07 20:31:232411def _CheckForWindowsLineEndings(input_api, output_api):
2412 """Check source code and known ascii text files for Windows style line
2413 endings.
2414 """
earthdok1b5e0ee2015-03-10 15:19:102415 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232416
2417 file_inclusion_pattern = (
2418 known_text_files,
2419 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2420 )
2421
2422 filter = lambda f: input_api.FilterSourceFile(
2423 f, white_list=file_inclusion_pattern, black_list=None)
2424 files = [f.LocalPath() for f in
2425 input_api.AffectedSourceFiles(filter)]
2426
2427 problems = []
2428
2429 for file in files:
2430 fp = open(file, 'r')
2431 for line in fp:
2432 if line.endswith('\r\n'):
2433 problems.append(file)
2434 break
2435 fp.close()
2436
2437 if problems:
2438 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2439 'these files to contain Windows style line endings?\n' +
2440 '\n'.join(problems))]
2441
2442 return []
2443
2444
pastarmovj89f7ee12016-09-20 14:58:132445def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2446 lint_filters=None, verbose_level=None):
2447 """Checks that all source files use SYSLOG properly."""
2448 syslog_files = []
2449 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562450 for line_number, line in f.ChangedContents():
2451 if 'SYSLOG' in line:
2452 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2453
pastarmovj89f7ee12016-09-20 14:58:132454 if syslog_files:
2455 return [output_api.PresubmitPromptWarning(
2456 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2457 ' calls.\nFiles to check:\n', items=syslog_files)]
2458 return []
2459
2460
[email protected]1f7b4172010-01-28 01:17:342461def CheckChangeOnUpload(input_api, output_api):
2462 results = []
2463 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472464 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282465 results.extend(
jam93a6ee792017-02-08 23:59:222466 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192467 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222468 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132469 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162470 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542471 return results
[email protected]ca8d19842009-02-19 16:33:122472
2473
[email protected]1bfb8322014-04-23 01:02:412474def GetTryServerMasterForBot(bot):
2475 """Returns the Try Server master for the given bot.
2476
[email protected]0bb112362014-07-26 04:38:322477 It tries to guess the master from the bot name, but may still fail
2478 and return None. There is no longer a default master.
2479 """
2480 # Potentially ambiguous bot names are listed explicitly.
2481 master_map = {
tandriie5587792016-07-14 00:34:502482 'chromium_presubmit': 'master.tryserver.chromium.linux',
2483 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412484 }
[email protected]0bb112362014-07-26 04:38:322485 master = master_map.get(bot)
2486 if not master:
wnwen4fbaab82016-05-25 12:54:362487 if 'android' in bot:
tandriie5587792016-07-14 00:34:502488 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362489 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502490 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322491 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502492 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322493 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502494 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322495 return master
[email protected]1bfb8322014-04-23 01:02:412496
2497
Paweł Hajdan, Jr55083782014-12-19 20:32:562498def GetDefaultTryConfigs(bots):
2499 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012500 """
2501
Paweł Hajdan, Jr55083782014-12-19 20:32:562502 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412503
2504 # Build up the mapping from tryserver master to bot/test.
2505 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562506 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412507 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2508 return out
[email protected]38c6a512013-12-18 23:48:012509
2510
[email protected]ca8d19842009-02-19 16:33:122511def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542512 results = []
[email protected]1f7b4172010-01-28 01:17:342513 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542514 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272515 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342516 input_api,
2517 output_api,
[email protected]2fdd1f362013-01-16 03:56:032518 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272519
jam93a6ee792017-02-08 23:59:222520 results.extend(
2521 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542522 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2523 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412524 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2525 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542526 return results