blob: 215ffbcfde47d1884a876237342d95a379a53397 [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 (
[email protected]23e6cbc2012-06-16 18:51:20192 'ScopedAllowIO',
193 (
[email protected]e3c945502012-06-26 20:01:49194 'New code should not use ScopedAllowIO. Post a task to the blocking',
195 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20196 ),
[email protected]e3c945502012-06-26 20:01:49197 True,
[email protected]7345da02012-11-27 14:31:49198 (
hajimehoshi2acea432017-03-08 08:55:37199 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
rayb0088ee52017-04-26 22:35:08200 r"^base[\\\/]process[\\\/]internal_aix\.cc$",
nyad2c548b2015-12-09 03:22:32201 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10202 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22203 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31204 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51205 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
206 "customization_document_browsertest\.cc$",
Asanka Herath2ea5bc12017-05-26 17:30:46207 r"^chrome[\\\/]test[\\\/]ppapi[\\\/]ppapi_filechooser_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09208 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49209 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
210 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25211 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41212 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
213 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25214 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48215 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
216 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01217 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25218 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
219 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
220 r"embedded_test_server\.cc$",
221 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
222 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54223 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16224 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53225 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
226 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45227 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
228 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
229 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
230 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
231 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49232 ),
[email protected]23e6cbc2012-06-16 18:51:20233 ),
[email protected]52657f62013-05-20 05:30:31234 (
tomhudsone2c14d552016-05-26 17:07:46235 'setMatrixClip',
236 (
237 'Overriding setMatrixClip() is prohibited; ',
238 'the base function is deprecated. ',
239 ),
240 True,
241 (),
242 ),
243 (
[email protected]52657f62013-05-20 05:30:31244 'SkRefPtr',
245 (
246 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22247 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31248 ),
249 True,
250 (),
251 ),
252 (
253 'SkAutoRef',
254 (
255 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22256 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31257 ),
258 True,
259 (),
260 ),
261 (
262 'SkAutoTUnref',
263 (
264 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22265 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31266 ),
267 True,
268 (),
269 ),
270 (
271 'SkAutoUnref',
272 (
273 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
274 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22275 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31276 ),
277 True,
278 (),
279 ),
[email protected]d89eec82013-12-03 14:10:59280 (
281 r'/HANDLE_EINTR\(.*close',
282 (
283 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
284 'descriptor will be closed, and it is incorrect to retry the close.',
285 'Either call close directly and ignore its return value, or wrap close',
286 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
287 ),
288 True,
289 (),
290 ),
291 (
292 r'/IGNORE_EINTR\((?!.*close)',
293 (
294 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
295 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
296 ),
297 True,
298 (
299 # Files that #define IGNORE_EINTR.
300 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
301 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
302 ),
303 ),
[email protected]ec5b3f02014-04-04 18:43:43304 (
305 r'/v8::Extension\(',
306 (
307 'Do not introduce new v8::Extensions into the code base, use',
308 'gin::Wrappable instead. See http://crbug.com/334679',
309 ),
310 True,
[email protected]f55c90ee62014-04-12 00:50:03311 (
joaodasilva718f87672014-08-30 09:25:49312 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03313 ),
[email protected]ec5b3f02014-04-04 18:43:43314 ),
skyostilf9469f72015-04-20 10:38:52315 (
jame2d1a952016-04-02 00:27:10316 '#pragma comment(lib,',
317 (
318 'Specify libraries to link with in build files and not in the source.',
319 ),
320 True,
321 (),
322 ),
fdorayc4ac18d2017-05-01 21:39:59323 (
324 'BrowserThread::GetBlockingPool',
325 (
326 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
327 'mapping between both APIs in content/public/browser/browser_thread.h.',
328 'For questions, contact base/task_scheduler/OWNERS.',
329 ),
330 True,
331 (),
332 ),
gabd52c912a2017-05-11 04:15:59333 (
334 'base::NonThreadSafe',
335 (
336 'base::NonThreadSafe is deprecated.',
337 ),
338 True,
339 (),
340 ),
341 (
342 'base::SequenceChecker',
343 (
344 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
345 ),
346 False,
347 (),
348 ),
349 (
350 'base::ThreadChecker',
351 (
352 'Consider using THREAD_CHECKER macros instead of the class directly.',
353 ),
354 False,
355 (),
356 ),
[email protected]127f18ec2012-06-16 05:05:59357)
358
wnwenbdc444e2016-05-25 13:44:15359
mlamouria82272622014-09-16 18:45:04360_IPC_ENUM_TRAITS_DEPRECATED = (
361 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
362 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
363
[email protected]127f18ec2012-06-16 05:05:59364
[email protected]b00342e7f2013-03-26 16:21:54365_VALID_OS_MACROS = (
366 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08367 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54368 'OS_ANDROID',
369 'OS_BSD',
370 'OS_CAT', # For testing.
371 'OS_CHROMEOS',
372 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37373 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54374 'OS_IOS',
375 'OS_LINUX',
376 'OS_MACOSX',
377 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21378 'OS_NACL_NONSFI',
379 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12380 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54381 'OS_OPENBSD',
382 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37383 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54384 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54385 'OS_WIN',
386)
387
388
agrievef32bcc72016-04-04 14:57:40389_ANDROID_SPECIFIC_PYDEPS_FILES = [
390 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04391 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58392 'build/secondary/third_party/android_platform/'
393 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19394 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40395]
396
wnwenbdc444e2016-05-25 13:44:15397
agrievef32bcc72016-04-04 14:57:40398_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40399]
400
wnwenbdc444e2016-05-25 13:44:15401
agrievef32bcc72016-04-04 14:57:40402_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
403
404
[email protected]55459852011-08-10 15:17:19405def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
406 """Attempts to prevent use of functions intended only for testing in
407 non-testing code. For now this is just a best-effort implementation
408 that ignores header files and may have some false positives. A
409 better implementation would probably need a proper C++ parser.
410 """
411 # We only scan .cc files and the like, as the declaration of
412 # for-testing functions in header files are hard to distinguish from
413 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44414 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19415
jochenc0d4808c2015-07-27 09:25:42416 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19417 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09418 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19419 exclusion_pattern = input_api.re.compile(
420 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
421 base_function_pattern, base_function_pattern))
422
423 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44424 black_list = (_EXCLUDED_PATHS +
425 _TEST_CODE_EXCLUDED_PATHS +
426 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19427 return input_api.FilterSourceFile(
428 affected_file,
429 white_list=(file_inclusion_pattern, ),
430 black_list=black_list)
431
432 problems = []
433 for f in input_api.AffectedSourceFiles(FilterFile):
434 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24435 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03436 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46437 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03438 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19439 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03440 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19441
442 if problems:
[email protected]f7051d52013-04-02 18:31:42443 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03444 else:
445 return []
[email protected]55459852011-08-10 15:17:19446
447
[email protected]10689ca2011-09-02 02:31:54448def _CheckNoIOStreamInHeaders(input_api, output_api):
449 """Checks to make sure no .h files include <iostream>."""
450 files = []
451 pattern = input_api.re.compile(r'^#include\s*<iostream>',
452 input_api.re.MULTILINE)
453 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
454 if not f.LocalPath().endswith('.h'):
455 continue
456 contents = input_api.ReadFile(f)
457 if pattern.search(contents):
458 files.append(f)
459
460 if len(files):
yolandyandaabc6d2016-04-18 18:29:39461 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06462 'Do not #include <iostream> in header files, since it inserts static '
463 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54464 '#include <ostream>. See http://crbug.com/94794',
465 files) ]
466 return []
467
468
[email protected]72df4e782012-06-21 16:28:18469def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52470 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18471 problems = []
472 for f in input_api.AffectedFiles():
473 if (not f.LocalPath().endswith(('.cc', '.mm'))):
474 continue
475
476 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04477 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18478 problems.append(' %s:%d' % (f.LocalPath(), line_num))
479
480 if not problems:
481 return []
482 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
483 '\n'.join(problems))]
484
485
danakj61c1aa22015-10-26 19:55:52486def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57487 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52488 errors = []
489 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
490 input_api.re.MULTILINE)
491 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
492 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
493 continue
494 for lnum, line in f.ChangedContents():
495 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17496 errors.append(output_api.PresubmitError(
497 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57498 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17499 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52500 return errors
501
502
mcasasb7440c282015-02-04 14:52:19503def _FindHistogramNameInLine(histogram_name, line):
504 """Tries to find a histogram name or prefix in a line."""
505 if not "affected-histogram" in line:
506 return histogram_name in line
507 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
508 # the histogram_name.
509 if not '"' in line:
510 return False
511 histogram_prefix = line.split('\"')[1]
512 return histogram_prefix in histogram_name
513
514
515def _CheckUmaHistogramChanges(input_api, output_api):
516 """Check that UMA histogram names in touched lines can still be found in other
517 lines of the patch or in histograms.xml. Note that this check would not catch
518 the reverse: changes in histograms.xml not matched in the code itself."""
519 touched_histograms = []
520 histograms_xml_modifications = []
521 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
522 for f in input_api.AffectedFiles():
523 # If histograms.xml itself is modified, keep the modified lines for later.
524 if f.LocalPath().endswith(('histograms.xml')):
525 histograms_xml_modifications = f.ChangedContents()
526 continue
527 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
528 continue
529 for line_num, line in f.ChangedContents():
530 found = pattern.search(line)
531 if found:
532 touched_histograms.append([found.group(1), f, line_num])
533
534 # Search for the touched histogram names in the local modifications to
535 # histograms.xml, and, if not found, on the base histograms.xml file.
536 unmatched_histograms = []
537 for histogram_info in touched_histograms:
538 histogram_name_found = False
539 for line_num, line in histograms_xml_modifications:
540 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
541 if histogram_name_found:
542 break
543 if not histogram_name_found:
544 unmatched_histograms.append(histogram_info)
545
eromanb90c82e7e32015-04-01 15:13:49546 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19547 problems = []
548 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49549 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19550 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45551 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19552 histogram_name_found = False
553 for line in histograms_xml:
554 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
555 if histogram_name_found:
556 break
557 if not histogram_name_found:
558 problems.append(' [%s:%d] %s' %
559 (f.LocalPath(), line_num, histogram_name))
560
561 if not problems:
562 return []
563 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
564 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49565 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19566
wnwenbdc444e2016-05-25 13:44:15567
yolandyandaabc6d2016-04-18 18:29:39568def _CheckFlakyTestUsage(input_api, output_api):
569 """Check that FlakyTest annotation is our own instead of the android one"""
570 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
571 files = []
572 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
573 if f.LocalPath().endswith('Test.java'):
574 if pattern.search(input_api.ReadFile(f)):
575 files.append(f)
576 if len(files):
577 return [output_api.PresubmitError(
578 'Use org.chromium.base.test.util.FlakyTest instead of '
579 'android.test.FlakyTest',
580 files)]
581 return []
mcasasb7440c282015-02-04 14:52:19582
wnwenbdc444e2016-05-25 13:44:15583
[email protected]8ea5d4b2011-09-13 21:49:22584def _CheckNoNewWStrings(input_api, output_api):
585 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27586 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22587 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20588 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57589 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34590 '/win/' in f.LocalPath() or
591 'chrome_elf' in f.LocalPath() or
592 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20593 continue
[email protected]8ea5d4b2011-09-13 21:49:22594
[email protected]a11dbe9b2012-08-07 01:32:58595 allowWString = False
[email protected]b5c24292011-11-28 14:38:20596 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58597 if 'presubmit: allow wstring' in line:
598 allowWString = True
599 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27600 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58601 allowWString = False
602 else:
603 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22604
[email protected]55463aa62011-10-12 00:48:27605 if not problems:
606 return []
607 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58608 ' If you are calling a cross-platform API that accepts a wstring, '
609 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27610 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22611
612
[email protected]2a8ac9c2011-10-19 17:20:44613def _CheckNoDEPSGIT(input_api, output_api):
614 """Make sure .DEPS.git is never modified manually."""
615 if any(f.LocalPath().endswith('.DEPS.git') for f in
616 input_api.AffectedFiles()):
617 return [output_api.PresubmitError(
618 'Never commit changes to .DEPS.git. This file is maintained by an\n'
619 'automated system based on what\'s in DEPS and your changes will be\n'
620 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34621 '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:44622 'for more information')]
623 return []
624
625
tandriief664692014-09-23 14:51:47626def _CheckValidHostsInDEPS(input_api, output_api):
627 """Checks that DEPS file deps are from allowed_hosts."""
628 # Run only if DEPS file has been modified to annoy fewer bystanders.
629 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
630 return []
631 # Outsource work to gclient verify
632 try:
633 input_api.subprocess.check_output(['gclient', 'verify'])
634 return []
635 except input_api.subprocess.CalledProcessError, error:
636 return [output_api.PresubmitError(
637 'DEPS file must have only git dependencies.',
638 long_text=error.output)]
639
640
[email protected]127f18ec2012-06-16 05:05:59641def _CheckNoBannedFunctions(input_api, output_api):
642 """Make sure that banned functions are not used."""
643 warnings = []
644 errors = []
645
wnwenbdc444e2016-05-25 13:44:15646 def IsBlacklisted(affected_file, blacklist):
647 local_path = affected_file.LocalPath()
648 for item in blacklist:
649 if input_api.re.match(item, local_path):
650 return True
651 return False
652
653 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
654 matched = False
655 if func_name[0:1] == '/':
656 regex = func_name[1:]
657 if input_api.re.search(regex, line):
658 matched = True
659 elif func_name in line:
dchenge07de812016-06-20 19:27:17660 matched = True
wnwenbdc444e2016-05-25 13:44:15661 if matched:
dchenge07de812016-06-20 19:27:17662 problems = warnings
wnwenbdc444e2016-05-25 13:44:15663 if error:
dchenge07de812016-06-20 19:27:17664 problems = errors
wnwenbdc444e2016-05-25 13:44:15665 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
666 for message_line in message:
667 problems.append(' %s' % message_line)
668
[email protected]127f18ec2012-06-16 05:05:59669 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
670 for f in input_api.AffectedFiles(file_filter=file_filter):
671 for line_num, line in f.ChangedContents():
672 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15673 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59674
675 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
676 for f in input_api.AffectedFiles(file_filter=file_filter):
677 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49678 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49679 if IsBlacklisted(f, excluded_paths):
680 continue
wnwenbdc444e2016-05-25 13:44:15681 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59682
683 result = []
684 if (warnings):
685 result.append(output_api.PresubmitPromptWarning(
686 'Banned functions were used.\n' + '\n'.join(warnings)))
687 if (errors):
688 result.append(output_api.PresubmitError(
689 'Banned functions were used.\n' + '\n'.join(errors)))
690 return result
691
692
[email protected]6c063c62012-07-11 19:11:06693def _CheckNoPragmaOnce(input_api, output_api):
694 """Make sure that banned functions are not used."""
695 files = []
696 pattern = input_api.re.compile(r'^#pragma\s+once',
697 input_api.re.MULTILINE)
698 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
699 if not f.LocalPath().endswith('.h'):
700 continue
701 contents = input_api.ReadFile(f)
702 if pattern.search(contents):
703 files.append(f)
704
705 if files:
706 return [output_api.PresubmitError(
707 'Do not use #pragma once in header files.\n'
708 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
709 files)]
710 return []
711
[email protected]127f18ec2012-06-16 05:05:59712
[email protected]e7479052012-09-19 00:26:12713def _CheckNoTrinaryTrueFalse(input_api, output_api):
714 """Checks to make sure we don't introduce use of foo ? true : false."""
715 problems = []
716 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
717 for f in input_api.AffectedFiles():
718 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
719 continue
720
721 for line_num, line in f.ChangedContents():
722 if pattern.match(line):
723 problems.append(' %s:%d' % (f.LocalPath(), line_num))
724
725 if not problems:
726 return []
727 return [output_api.PresubmitPromptWarning(
728 'Please consider avoiding the "? true : false" pattern if possible.\n' +
729 '\n'.join(problems))]
730
731
[email protected]55f9f382012-07-31 11:02:18732def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28733 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18734 change. Breaking - rules is an error, breaking ! rules is a
735 warning.
736 """
mohan.reddyf21db962014-10-16 12:26:47737 import sys
[email protected]55f9f382012-07-31 11:02:18738 # We need to wait until we have an input_api object and use this
739 # roundabout construct to import checkdeps because this file is
740 # eval-ed and thus doesn't have __file__.
741 original_sys_path = sys.path
742 try:
743 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47744 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18745 import checkdeps
746 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28747 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18748 from rules import Rule
749 finally:
750 # Restore sys.path to what it was before.
751 sys.path = original_sys_path
752
753 added_includes = []
rhalavati08acd232017-04-03 07:23:28754 added_imports = []
[email protected]55f9f382012-07-31 11:02:18755 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28756 if CppChecker.IsCppFile(f.LocalPath()):
757 changed_lines = [line for line_num, line in f.ChangedContents()]
758 added_includes.append([f.LocalPath(), changed_lines])
759 elif ProtoChecker.IsProtoFile(f.LocalPath()):
760 changed_lines = [line for line_num, line in f.ChangedContents()]
761 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18762
[email protected]26385172013-05-09 23:11:35763 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18764
765 error_descriptions = []
766 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28767 error_subjects = set()
768 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18769 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
770 added_includes):
771 description_with_path = '%s\n %s' % (path, rule_description)
772 if rule_type == Rule.DISALLOW:
773 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28774 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18775 else:
776 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28777 warning_subjects.add("#includes")
778
779 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
780 added_imports):
781 description_with_path = '%s\n %s' % (path, rule_description)
782 if rule_type == Rule.DISALLOW:
783 error_descriptions.append(description_with_path)
784 error_subjects.add("imports")
785 else:
786 warning_descriptions.append(description_with_path)
787 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18788
789 results = []
790 if error_descriptions:
791 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28792 'You added one or more %s that violate checkdeps rules.'
793 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18794 error_descriptions))
795 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42796 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28797 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18798 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28799 '%s? See relevant DEPS file(s) for details and contacts.' %
800 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18801 warning_descriptions))
802 return results
803
804
[email protected]fbcafe5a2012-08-08 15:31:22805def _CheckFilePermissions(input_api, output_api):
806 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15807 if input_api.platform == 'win32':
808 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29809 checkperms_tool = input_api.os_path.join(
810 input_api.PresubmitLocalPath(),
811 'tools', 'checkperms', 'checkperms.py')
812 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47813 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22814 for f in input_api.AffectedFiles():
815 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11816 try:
817 input_api.subprocess.check_output(args)
818 return []
819 except input_api.subprocess.CalledProcessError as error:
820 return [output_api.PresubmitError(
821 'checkperms.py failed:',
822 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22823
824
robertocn832f5992017-01-04 19:01:30825def _CheckTeamTags(input_api, output_api):
826 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
827 checkteamtags_tool = input_api.os_path.join(
828 input_api.PresubmitLocalPath(),
829 'tools', 'checkteamtags', 'checkteamtags.py')
830 args = [input_api.python_executable, checkteamtags_tool,
831 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22832 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30833 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
834 'OWNERS']
835 try:
836 if files:
837 input_api.subprocess.check_output(args + files)
838 return []
839 except input_api.subprocess.CalledProcessError as error:
840 return [output_api.PresubmitError(
841 'checkteamtags.py failed:',
842 long_text=error.output)]
843
844
[email protected]c8278b32012-10-30 20:35:49845def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
846 """Makes sure we don't include ui/aura/window_property.h
847 in header files.
848 """
849 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
850 errors = []
851 for f in input_api.AffectedFiles():
852 if not f.LocalPath().endswith('.h'):
853 continue
854 for line_num, line in f.ChangedContents():
855 if pattern.match(line):
856 errors.append(' %s:%d' % (f.LocalPath(), line_num))
857
858 results = []
859 if errors:
860 results.append(output_api.PresubmitError(
861 'Header files should not include ui/aura/window_property.h', errors))
862 return results
863
864
[email protected]cf9b78f2012-11-14 11:40:28865def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
866 """Checks that the lines in scope occur in the right order.
867
868 1. C system files in alphabetical order
869 2. C++ system files in alphabetical order
870 3. Project's .h files
871 """
872
873 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
874 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
875 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
876
877 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
878
879 state = C_SYSTEM_INCLUDES
880
881 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57882 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28883 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55884 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28885 for line_num, line in scope:
886 if c_system_include_pattern.match(line):
887 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55888 problem_linenums.append((line_num, previous_line_num,
889 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28890 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55891 problem_linenums.append((line_num, previous_line_num,
892 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28893 elif cpp_system_include_pattern.match(line):
894 if state == C_SYSTEM_INCLUDES:
895 state = CPP_SYSTEM_INCLUDES
896 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55897 problem_linenums.append((line_num, previous_line_num,
898 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28899 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55900 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28901 elif custom_include_pattern.match(line):
902 if state != CUSTOM_INCLUDES:
903 state = CUSTOM_INCLUDES
904 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55905 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28906 else:
brucedawson70fadb02015-06-30 17:47:55907 problem_linenums.append((line_num, previous_line_num,
908 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28909 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57910 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28911
912 warnings = []
brucedawson70fadb02015-06-30 17:47:55913 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57914 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55915 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28916 return warnings
917
918
[email protected]ac294a12012-12-06 16:38:43919def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28920 """Checks the #include order for the given file f."""
921
[email protected]2299dcf2012-11-15 19:56:24922 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30923 # Exclude the following includes from the check:
924 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
925 # specific order.
926 # 2) <atlbase.h>, "build/build_config.h"
927 excluded_include_pattern = input_api.re.compile(
928 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24929 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33930 # Match the final or penultimate token if it is xxxtest so we can ignore it
931 # when considering the special first include.
932 test_file_tag_pattern = input_api.re.compile(
933 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11934 if_pattern = input_api.re.compile(
935 r'\s*#\s*(if|elif|else|endif|define|undef).*')
936 # Some files need specialized order of includes; exclude such files from this
937 # check.
938 uncheckable_includes_pattern = input_api.re.compile(
939 r'\s*#include '
940 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28941
942 contents = f.NewContents()
943 warnings = []
944 line_num = 0
945
[email protected]ac294a12012-12-06 16:38:43946 # Handle the special first include. If the first include file is
947 # some/path/file.h, the corresponding including file can be some/path/file.cc,
948 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
949 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33950 # If the included file is some/path/file_platform.h the including file could
951 # also be some/path/file_xxxtest_platform.h.
952 including_file_base_name = test_file_tag_pattern.sub(
953 '', input_api.os_path.basename(f.LocalPath()))
954
[email protected]ac294a12012-12-06 16:38:43955 for line in contents:
956 line_num += 1
957 if system_include_pattern.match(line):
958 # No special first include -> process the line again along with normal
959 # includes.
960 line_num -= 1
961 break
962 match = custom_include_pattern.match(line)
963 if match:
964 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33965 header_basename = test_file_tag_pattern.sub(
966 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
967
968 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24969 # No special first include -> process the line again along with normal
970 # includes.
971 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43972 break
[email protected]cf9b78f2012-11-14 11:40:28973
974 # Split into scopes: Each region between #if and #endif is its own scope.
975 scopes = []
976 current_scope = []
977 for line in contents[line_num:]:
978 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11979 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54980 continue
[email protected]2309b0fa02012-11-16 12:18:27981 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28982 scopes.append(current_scope)
983 current_scope = []
[email protected]962f117e2012-11-22 18:11:56984 elif ((system_include_pattern.match(line) or
985 custom_include_pattern.match(line)) and
986 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28987 current_scope.append((line_num, line))
988 scopes.append(current_scope)
989
990 for scope in scopes:
991 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
992 changed_linenums))
993 return warnings
994
995
996def _CheckIncludeOrder(input_api, output_api):
997 """Checks that the #include order is correct.
998
999 1. The corresponding header for source files.
1000 2. C system files in alphabetical order
1001 3. C++ system files in alphabetical order
1002 4. Project's .h files in alphabetical order
1003
[email protected]ac294a12012-12-06 16:38:431004 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
1005 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:281006 """
[email protected]e120b012014-08-15 19:08:351007 def FileFilterIncludeOrder(affected_file):
1008 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
1009 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:281010
1011 warnings = []
[email protected]e120b012014-08-15 19:08:351012 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:081013 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:431014 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
1015 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:281016
1017 results = []
1018 if warnings:
[email protected]f7051d52013-04-02 18:31:421019 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:531020 warnings))
[email protected]cf9b78f2012-11-14 11:40:281021 return results
1022
1023
[email protected]70ca77752012-11-20 03:45:031024def _CheckForVersionControlConflictsInFile(input_api, f):
1025 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1026 errors = []
1027 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231028 if f.LocalPath().endswith('.md'):
1029 # First-level headers in markdown look a lot like version control
1030 # conflict markers. http://daringfireball.net/projects/markdown/basics
1031 continue
[email protected]70ca77752012-11-20 03:45:031032 if pattern.match(line):
1033 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1034 return errors
1035
1036
1037def _CheckForVersionControlConflicts(input_api, output_api):
1038 """Usually this is not intentional and will cause a compile failure."""
1039 errors = []
1040 for f in input_api.AffectedFiles():
1041 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1042
1043 results = []
1044 if errors:
1045 results.append(output_api.PresubmitError(
1046 'Version control conflict markers found, please resolve.', errors))
1047 return results
1048
estadee17314a02017-01-12 16:22:161049def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1050 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1051 errors = []
1052 for f in input_api.AffectedFiles():
1053 for line_num, line in f.ChangedContents():
1054 if pattern.search(line):
1055 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1056
1057 results = []
1058 if errors:
1059 results.append(output_api.PresubmitPromptWarning(
1060 'Found Google support URL addressed by answer number. Please replace with '
1061 'a p= identifier instead. See crbug.com/679462\n', errors))
1062 return results
1063
[email protected]70ca77752012-11-20 03:45:031064
[email protected]06e6d0ff2012-12-11 01:36:441065def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1066 def FilterFile(affected_file):
1067 """Filter function for use with input_api.AffectedSourceFiles,
1068 below. This filters out everything except non-test files from
1069 top-level directories that generally speaking should not hard-code
1070 service URLs (e.g. src/android_webview/, src/content/ and others).
1071 """
1072 return input_api.FilterSourceFile(
1073 affected_file,
[email protected]78bb39d62012-12-11 15:11:561074 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441075 black_list=(_EXCLUDED_PATHS +
1076 _TEST_CODE_EXCLUDED_PATHS +
1077 input_api.DEFAULT_BLACK_LIST))
1078
reillyi38965732015-11-16 18:27:331079 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1080 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461081 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1082 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441083 problems = [] # items are (filename, line_number, line)
1084 for f in input_api.AffectedSourceFiles(FilterFile):
1085 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461086 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441087 problems.append((f.LocalPath(), line_num, line))
1088
1089 if problems:
[email protected]f7051d52013-04-02 18:31:421090 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441091 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581092 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441093 [' %s:%d: %s' % (
1094 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031095 else:
1096 return []
[email protected]06e6d0ff2012-12-11 01:36:441097
1098
[email protected]d2530012013-01-25 16:39:271099def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1100 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311101 The native_client_sdk directory is excluded because it has auto-generated PNG
1102 files for documentation.
[email protected]d2530012013-01-25 16:39:271103 """
[email protected]d2530012013-01-25 16:39:271104 errors = []
binji0dcdf342014-12-12 18:32:311105 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1106 black_list = (r'^native_client_sdk[\\\/]',)
1107 file_filter = lambda f: input_api.FilterSourceFile(
1108 f, white_list=white_list, black_list=black_list)
1109 for f in input_api.AffectedFiles(include_deletes=False,
1110 file_filter=file_filter):
1111 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271112
1113 results = []
1114 if errors:
1115 results.append(output_api.PresubmitError(
1116 'The name of PNG files should not have abbreviations. \n'
1117 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1118 'Contact [email protected] if you have questions.', errors))
1119 return results
1120
1121
Daniel Cheng4dcdb6b2017-04-13 08:30:171122def _ExtractAddRulesFromParsedDeps(parsed_deps):
1123 """Extract the rules that add dependencies from a parsed DEPS file.
1124
1125 Args:
1126 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1127 add_rules = set()
1128 add_rules.update([
1129 rule[1:] for rule in parsed_deps.get('include_rules', [])
1130 if rule.startswith('+') or rule.startswith('!')
1131 ])
1132 for specific_file, rules in parsed_deps.get('specific_include_rules',
1133 {}).iteritems():
1134 add_rules.update([
1135 rule[1:] for rule in rules
1136 if rule.startswith('+') or rule.startswith('!')
1137 ])
1138 return add_rules
1139
1140
1141def _ParseDeps(contents):
1142 """Simple helper for parsing DEPS files."""
1143 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171144 class _VarImpl:
1145
1146 def __init__(self, local_scope):
1147 self._local_scope = local_scope
1148
1149 def Lookup(self, var_name):
1150 """Implements the Var syntax."""
1151 try:
1152 return self._local_scope['vars'][var_name]
1153 except KeyError:
1154 raise Exception('Var is not defined: %s' % var_name)
1155
1156 local_scope = {}
1157 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171158 'Var': _VarImpl(local_scope).Lookup,
1159 }
1160 exec contents in global_scope, local_scope
1161 return local_scope
1162
1163
1164def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081165 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411166 a set of DEPS entries that we should look up.
1167
1168 For a directory (rather than a specific filename) we fake a path to
1169 a specific filename by adding /DEPS. This is chosen as a file that
1170 will seldom or never be subject to per-file include_rules.
1171 """
[email protected]2b438d62013-11-14 17:54:141172 # We ignore deps entries on auto-generated directories.
1173 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081174
Daniel Cheng4dcdb6b2017-04-13 08:30:171175 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1176 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1177
1178 added_deps = new_deps.difference(old_deps)
1179
[email protected]2b438d62013-11-14 17:54:141180 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171181 for added_dep in added_deps:
1182 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1183 continue
1184 # Assume that a rule that ends in .h is a rule for a specific file.
1185 if added_dep.endswith('.h'):
1186 results.add(added_dep)
1187 else:
1188 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081189 return results
1190
1191
[email protected]e871964c2013-05-13 14:14:551192def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1193 """When a dependency prefixed with + is added to a DEPS file, we
1194 want to make sure that the change is reviewed by an OWNER of the
1195 target file or directory, to avoid layering violations from being
1196 introduced. This check verifies that this happens.
1197 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171198 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241199
1200 file_filter = lambda f: not input_api.re.match(
1201 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1202 for f in input_api.AffectedFiles(include_deletes=False,
1203 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551204 filename = input_api.os_path.basename(f.LocalPath())
1205 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171206 virtual_depended_on_files.update(_CalculateAddedDeps(
1207 input_api.os_path,
1208 '\n'.join(f.OldContents()),
1209 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551210
[email protected]e871964c2013-05-13 14:14:551211 if not virtual_depended_on_files:
1212 return []
1213
1214 if input_api.is_committing:
1215 if input_api.tbr:
1216 return [output_api.PresubmitNotifyResult(
1217 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271218 if input_api.dry_run:
1219 return [output_api.PresubmitNotifyResult(
1220 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551221 if not input_api.change.issue:
1222 return [output_api.PresubmitError(
1223 "DEPS approval by OWNERS check failed: this change has "
1224 "no Rietveld issue number, so we can't check it for approvals.")]
1225 output = output_api.PresubmitError
1226 else:
1227 output = output_api.PresubmitNotifyResult
1228
1229 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501230 owner_email, reviewers = (
1231 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1232 input_api,
1233 owners_db.email_regexp,
1234 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551235
1236 owner_email = owner_email or input_api.change.author_email
1237
[email protected]de4f7d22013-05-23 14:27:461238 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511239 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461240 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551241 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1242 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411243
1244 # We strip the /DEPS part that was added by
1245 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1246 # directory.
1247 def StripDeps(path):
1248 start_deps = path.rfind('/DEPS')
1249 if start_deps != -1:
1250 return path[:start_deps]
1251 else:
1252 return path
1253 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551254 for path in missing_files]
1255
1256 if unapproved_dependencies:
1257 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151258 output('You need LGTM from owners of depends-on paths in DEPS that were '
1259 'modified in this CL:\n %s' %
1260 '\n '.join(sorted(unapproved_dependencies)))]
1261 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1262 output_list.append(output(
1263 'Suggested missing target path OWNERS:\n %s' %
1264 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551265 return output_list
1266
1267 return []
1268
1269
[email protected]85218562013-11-22 07:41:401270def _CheckSpamLogging(input_api, output_api):
1271 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1272 black_list = (_EXCLUDED_PATHS +
1273 _TEST_CODE_EXCLUDED_PATHS +
1274 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501275 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191276 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481277 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461278 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121279 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1280 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581281 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161282 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031283 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151284 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1285 r"^chromecast[\\\/]",
1286 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481287 r"^components[\\\/]browser_watcher[\\\/]"
1288 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311289 r"^components[\\\/]html_viewer[\\\/]"
1290 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461291 # TODO(peter): Remove this exception. https://crbug.com/534537
1292 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1293 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251294 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1295 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241296 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111297 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151298 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111299 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521300 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501301 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361302 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311303 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131304 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001305 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441306 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451307 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021308 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351309 r"dump_file_system.cc$",
1310 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401311 source_file_filter = lambda x: input_api.FilterSourceFile(
1312 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1313
thomasanderson625d3932017-03-29 07:16:581314 log_info = set([])
1315 printf = set([])
[email protected]85218562013-11-22 07:41:401316
1317 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581318 for _, line in f.ChangedContents():
1319 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1320 log_info.add(f.LocalPath())
1321 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1322 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371323
thomasanderson625d3932017-03-29 07:16:581324 if input_api.re.search(r"\bprintf\(", line):
1325 printf.add(f.LocalPath())
1326 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1327 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401328
1329 if log_info:
1330 return [output_api.PresubmitError(
1331 'These files spam the console log with LOG(INFO):',
1332 items=log_info)]
1333 if printf:
1334 return [output_api.PresubmitError(
1335 'These files spam the console log with printf/fprintf:',
1336 items=printf)]
1337 return []
1338
1339
[email protected]49aa76a2013-12-04 06:59:161340def _CheckForAnonymousVariables(input_api, output_api):
1341 """These types are all expected to hold locks while in scope and
1342 so should never be anonymous (which causes them to be immediately
1343 destroyed)."""
1344 they_who_must_be_named = [
1345 'base::AutoLock',
1346 'base::AutoReset',
1347 'base::AutoUnlock',
1348 'SkAutoAlphaRestore',
1349 'SkAutoBitmapShaderInstall',
1350 'SkAutoBlitterChoose',
1351 'SkAutoBounderCommit',
1352 'SkAutoCallProc',
1353 'SkAutoCanvasRestore',
1354 'SkAutoCommentBlock',
1355 'SkAutoDescriptor',
1356 'SkAutoDisableDirectionCheck',
1357 'SkAutoDisableOvalCheck',
1358 'SkAutoFree',
1359 'SkAutoGlyphCache',
1360 'SkAutoHDC',
1361 'SkAutoLockColors',
1362 'SkAutoLockPixels',
1363 'SkAutoMalloc',
1364 'SkAutoMaskFreeImage',
1365 'SkAutoMutexAcquire',
1366 'SkAutoPathBoundsUpdate',
1367 'SkAutoPDFRelease',
1368 'SkAutoRasterClipValidate',
1369 'SkAutoRef',
1370 'SkAutoTime',
1371 'SkAutoTrace',
1372 'SkAutoUnref',
1373 ]
1374 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1375 # bad: base::AutoLock(lock.get());
1376 # not bad: base::AutoLock lock(lock.get());
1377 bad_pattern = input_api.re.compile(anonymous)
1378 # good: new base::AutoLock(lock.get())
1379 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1380 errors = []
1381
1382 for f in input_api.AffectedFiles():
1383 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1384 continue
1385 for linenum, line in f.ChangedContents():
1386 if bad_pattern.search(line) and not good_pattern.search(line):
1387 errors.append('%s:%d' % (f.LocalPath(), linenum))
1388
1389 if errors:
1390 return [output_api.PresubmitError(
1391 'These lines create anonymous variables that need to be named:',
1392 items=errors)]
1393 return []
1394
1395
[email protected]5fe0f8742013-11-29 01:04:591396def _CheckCygwinShell(input_api, output_api):
1397 source_file_filter = lambda x: input_api.FilterSourceFile(
1398 x, white_list=(r'.+\.(gyp|gypi)$',))
1399 cygwin_shell = []
1400
1401 for f in input_api.AffectedSourceFiles(source_file_filter):
1402 for linenum, line in f.ChangedContents():
1403 if 'msvs_cygwin_shell' in line:
1404 cygwin_shell.append(f.LocalPath())
1405 break
1406
1407 if cygwin_shell:
1408 return [output_api.PresubmitError(
1409 'These files should not use msvs_cygwin_shell (the default is 0):',
1410 items=cygwin_shell)]
1411 return []
1412
[email protected]85218562013-11-22 07:41:401413
[email protected]999261d2014-03-03 20:08:081414def _CheckUserActionUpdate(input_api, output_api):
1415 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521416 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081417 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521418 # If actions.xml is already included in the changelist, the PRESUBMIT
1419 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081420 return []
1421
[email protected]999261d2014-03-03 20:08:081422 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1423 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521424 current_actions = None
[email protected]999261d2014-03-03 20:08:081425 for f in input_api.AffectedFiles(file_filter=file_filter):
1426 for line_num, line in f.ChangedContents():
1427 match = input_api.re.search(action_re, line)
1428 if match:
[email protected]2f92dec2014-03-07 19:21:521429 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1430 # loaded only once.
1431 if not current_actions:
1432 with open('tools/metrics/actions/actions.xml') as actions_f:
1433 current_actions = actions_f.read()
1434 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081435 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521436 action = 'name="{0}"'.format(action_name)
1437 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081438 return [output_api.PresubmitPromptWarning(
1439 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521440 'tools/metrics/actions/actions.xml. Please run '
1441 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081442 % (f.LocalPath(), line_num, action_name))]
1443 return []
1444
1445
[email protected]99171a92014-06-03 08:44:471446def _GetJSONParseError(input_api, filename, eat_comments=True):
1447 try:
1448 contents = input_api.ReadFile(filename)
1449 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131450 import sys
1451 original_sys_path = sys.path
1452 try:
1453 sys.path = sys.path + [input_api.os_path.join(
1454 input_api.PresubmitLocalPath(),
1455 'tools', 'json_comment_eater')]
1456 import json_comment_eater
1457 finally:
1458 sys.path = original_sys_path
1459 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471460
1461 input_api.json.loads(contents)
1462 except ValueError as e:
1463 return e
1464 return None
1465
1466
1467def _GetIDLParseError(input_api, filename):
1468 try:
1469 contents = input_api.ReadFile(filename)
1470 idl_schema = input_api.os_path.join(
1471 input_api.PresubmitLocalPath(),
1472 'tools', 'json_schema_compiler', 'idl_schema.py')
1473 process = input_api.subprocess.Popen(
1474 [input_api.python_executable, idl_schema],
1475 stdin=input_api.subprocess.PIPE,
1476 stdout=input_api.subprocess.PIPE,
1477 stderr=input_api.subprocess.PIPE,
1478 universal_newlines=True)
1479 (_, error) = process.communicate(input=contents)
1480 return error or None
1481 except ValueError as e:
1482 return e
1483
1484
1485def _CheckParseErrors(input_api, output_api):
1486 """Check that IDL and JSON files do not contain syntax errors."""
1487 actions = {
1488 '.idl': _GetIDLParseError,
1489 '.json': _GetJSONParseError,
1490 }
1491 # These paths contain test data and other known invalid JSON files.
1492 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491493 r'test[\\\/]data[\\\/]',
1494 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471495 ]
1496 # Most JSON files are preprocessed and support comments, but these do not.
1497 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491498 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471499 ]
1500 # Only run IDL checker on files in these directories.
1501 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491502 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1503 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471504 ]
1505
1506 def get_action(affected_file):
1507 filename = affected_file.LocalPath()
1508 return actions.get(input_api.os_path.splitext(filename)[1])
1509
1510 def MatchesFile(patterns, path):
1511 for pattern in patterns:
1512 if input_api.re.search(pattern, path):
1513 return True
1514 return False
1515
1516 def FilterFile(affected_file):
1517 action = get_action(affected_file)
1518 if not action:
1519 return False
1520 path = affected_file.LocalPath()
1521
1522 if MatchesFile(excluded_patterns, path):
1523 return False
1524
1525 if (action == _GetIDLParseError and
1526 not MatchesFile(idl_included_patterns, path)):
1527 return False
1528 return True
1529
1530 results = []
1531 for affected_file in input_api.AffectedFiles(
1532 file_filter=FilterFile, include_deletes=False):
1533 action = get_action(affected_file)
1534 kwargs = {}
1535 if (action == _GetJSONParseError and
1536 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1537 kwargs['eat_comments'] = False
1538 parse_error = action(input_api,
1539 affected_file.AbsoluteLocalPath(),
1540 **kwargs)
1541 if parse_error:
1542 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1543 (affected_file.LocalPath(), parse_error)))
1544 return results
1545
1546
[email protected]760deea2013-12-10 19:33:491547def _CheckJavaStyle(input_api, output_api):
1548 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471549 import sys
[email protected]760deea2013-12-10 19:33:491550 original_sys_path = sys.path
1551 try:
1552 sys.path = sys.path + [input_api.os_path.join(
1553 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1554 import checkstyle
1555 finally:
1556 # Restore sys.path to what it was before.
1557 sys.path = original_sys_path
1558
1559 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091560 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511561 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491562
1563
dchenge07de812016-06-20 19:27:171564def _CheckIpcOwners(input_api, output_api):
1565 """Checks that affected files involving IPC have an IPC OWNERS rule.
1566
1567 Whether or not a file affects IPC is determined by a simple whitelist of
1568 filename patterns."""
1569 file_patterns = [
palmerb19a0932017-01-24 04:00:311570 # Legacy IPC:
dchenge07de812016-06-20 19:27:171571 '*_messages.cc',
1572 '*_messages*.h',
1573 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311574 # Mojo IPC:
dchenge07de812016-06-20 19:27:171575 '*.mojom',
1576 '*_struct_traits*.*',
1577 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311578 '*.typemap',
1579 # Android native IPC:
1580 '*.aidl',
1581 # Blink uses a different file naming convention:
1582 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171583 '*StructTraits*.*',
1584 '*TypeConverter*.*',
1585 ]
1586
scottmg7a6ed5ba2016-11-04 18:22:041587 # These third_party directories do not contain IPCs, but contain files
1588 # matching the above patterns, which trigger false positives.
1589 exclude_paths = [
1590 'third_party/crashpad/*',
1591 ]
1592
dchenge07de812016-06-20 19:27:171593 # Dictionary mapping an OWNERS file path to Patterns.
1594 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1595 # rules ) to a PatternEntry.
1596 # PatternEntry is a dictionary with two keys:
1597 # - 'files': the files that are matched by this pattern
1598 # - 'rules': the per-file rules needed for this pattern
1599 # For example, if we expect OWNERS file to contain rules for *.mojom and
1600 # *_struct_traits*.*, Patterns might look like this:
1601 # {
1602 # '*.mojom': {
1603 # 'files': ...,
1604 # 'rules': [
1605 # 'per-file *.mojom=set noparent',
1606 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1607 # ],
1608 # },
1609 # '*_struct_traits*.*': {
1610 # 'files': ...,
1611 # 'rules': [
1612 # 'per-file *_struct_traits*.*=set noparent',
1613 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1614 # ],
1615 # },
1616 # }
1617 to_check = {}
1618
1619 # Iterate through the affected files to see what we actually need to check
1620 # for. We should only nag patch authors about per-file rules if a file in that
1621 # directory would match that pattern. If a directory only contains *.mojom
1622 # files and no *_messages*.h files, we should only nag about rules for
1623 # *.mojom files.
rockot51249332016-06-23 16:32:251624 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171625 for pattern in file_patterns:
1626 if input_api.fnmatch.fnmatch(
1627 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041628 skip = False
1629 for exclude in exclude_paths:
1630 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1631 skip = True
1632 break
1633 if skip:
1634 continue
dchenge07de812016-06-20 19:27:171635 owners_file = input_api.os_path.join(
1636 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1637 if owners_file not in to_check:
1638 to_check[owners_file] = {}
1639 if pattern not in to_check[owners_file]:
1640 to_check[owners_file][pattern] = {
1641 'files': [],
1642 'rules': [
1643 'per-file %s=set noparent' % pattern,
1644 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1645 ]
1646 }
1647 to_check[owners_file][pattern]['files'].append(f)
1648 break
1649
1650 # Now go through the OWNERS files we collected, filtering out rules that are
1651 # already present in that OWNERS file.
1652 for owners_file, patterns in to_check.iteritems():
1653 try:
1654 with file(owners_file) as f:
1655 lines = set(f.read().splitlines())
1656 for entry in patterns.itervalues():
1657 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1658 ]
1659 except IOError:
1660 # No OWNERS file, so all the rules are definitely missing.
1661 continue
1662
1663 # All the remaining lines weren't found in OWNERS files, so emit an error.
1664 errors = []
1665 for owners_file, patterns in to_check.iteritems():
1666 missing_lines = []
1667 files = []
1668 for pattern, entry in patterns.iteritems():
1669 missing_lines.extend(entry['rules'])
1670 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1671 if missing_lines:
1672 errors.append(
1673 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1674 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1675
1676 results = []
1677 if errors:
vabrf5ce3bf92016-07-11 14:52:411678 if input_api.is_committing:
1679 output = output_api.PresubmitError
1680 else:
1681 output = output_api.PresubmitPromptWarning
1682 results.append(output(
dchenge07de812016-06-20 19:27:171683 'Found changes to IPC files without a security OWNER!',
1684 long_text='\n\n'.join(errors)))
1685
1686 return results
1687
1688
jbriance9e12f162016-11-25 07:57:501689def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311690 """Checks that added or removed lines in non third party affected
1691 header files do not lead to new useless class or struct forward
1692 declaration.
jbriance9e12f162016-11-25 07:57:501693 """
1694 results = []
1695 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1696 input_api.re.MULTILINE)
1697 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1698 input_api.re.MULTILINE)
1699 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311700 if (f.LocalPath().startswith('third_party') and
1701 not f.LocalPath().startswith('third_party/WebKit') and
1702 not f.LocalPath().startswith('third_party\\WebKit')):
1703 continue
1704
jbriance9e12f162016-11-25 07:57:501705 if not f.LocalPath().endswith('.h'):
1706 continue
1707
1708 contents = input_api.ReadFile(f)
1709 fwd_decls = input_api.re.findall(class_pattern, contents)
1710 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1711
1712 useless_fwd_decls = []
1713 for decl in fwd_decls:
1714 count = sum(1 for _ in input_api.re.finditer(
1715 r'\b%s\b' % input_api.re.escape(decl), contents))
1716 if count == 1:
1717 useless_fwd_decls.append(decl)
1718
1719 if not useless_fwd_decls:
1720 continue
1721
1722 for line in f.GenerateScmDiff().splitlines():
1723 if (line.startswith('-') and not line.startswith('--') or
1724 line.startswith('+') and not line.startswith('++')):
1725 for decl in useless_fwd_decls:
1726 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1727 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241728 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501729 (f.LocalPath(), decl)))
1730 useless_fwd_decls.remove(decl)
1731
1732 return results
1733
1734
dskiba88634f4e2015-08-14 23:03:291735def _CheckAndroidToastUsage(input_api, output_api):
1736 """Checks that code uses org.chromium.ui.widget.Toast instead of
1737 android.widget.Toast (Chromium Toast doesn't force hardware
1738 acceleration on low-end devices, saving memory).
1739 """
1740 toast_import_pattern = input_api.re.compile(
1741 r'^import android\.widget\.Toast;$')
1742
1743 errors = []
1744
1745 sources = lambda affected_file: input_api.FilterSourceFile(
1746 affected_file,
1747 black_list=(_EXCLUDED_PATHS +
1748 _TEST_CODE_EXCLUDED_PATHS +
1749 input_api.DEFAULT_BLACK_LIST +
1750 (r'^chromecast[\\\/].*',
1751 r'^remoting[\\\/].*')),
1752 white_list=(r'.*\.java$',))
1753
1754 for f in input_api.AffectedSourceFiles(sources):
1755 for line_num, line in f.ChangedContents():
1756 if toast_import_pattern.search(line):
1757 errors.append("%s:%d" % (f.LocalPath(), line_num))
1758
1759 results = []
1760
1761 if errors:
1762 results.append(output_api.PresubmitError(
1763 'android.widget.Toast usage is detected. Android toasts use hardware'
1764 ' acceleration, and can be\ncostly on low-end devices. Please use'
1765 ' org.chromium.ui.widget.Toast instead.\n'
1766 'Contact [email protected] if you have any questions.',
1767 errors))
1768
1769 return results
1770
1771
dgnaa68d5e2015-06-10 10:08:221772def _CheckAndroidCrLogUsage(input_api, output_api):
1773 """Checks that new logs using org.chromium.base.Log:
1774 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511775 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221776 """
pkotwicza1dd0b002016-05-16 14:41:041777
torne89540622017-03-24 19:41:301778 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041779 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301780 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041781 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301782 # WebView license viewer code cannot depend on //base; used in stub APK.
1783 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1784 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041785 ]
1786
dgnaa68d5e2015-06-10 10:08:221787 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121788 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1789 class_in_base_pattern = input_api.re.compile(
1790 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1791 has_some_log_import_pattern = input_api.re.compile(
1792 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221793 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121794 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221795 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511796 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221797 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221798
Vincent Scheib16d7b272015-09-15 18:09:071799 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221800 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041801 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1802 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121803
dgnaa68d5e2015-06-10 10:08:221804 tag_decl_errors = []
1805 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121806 tag_errors = []
dgn38736db2015-09-18 19:20:511807 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121808 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221809
1810 for f in input_api.AffectedSourceFiles(sources):
1811 file_content = input_api.ReadFile(f)
1812 has_modified_logs = False
1813
1814 # Per line checks
dgn87d9fb62015-06-12 09:15:121815 if (cr_log_import_pattern.search(file_content) or
1816 (class_in_base_pattern.search(file_content) and
1817 not has_some_log_import_pattern.search(file_content))):
1818 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221819 for line_num, line in f.ChangedContents():
1820
1821 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121822 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221823 if match:
1824 has_modified_logs = True
1825
1826 # Make sure it uses "TAG"
1827 if not match.group('tag') == 'TAG':
1828 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121829 else:
1830 # Report non cr Log function calls in changed lines
1831 for line_num, line in f.ChangedContents():
1832 if log_call_pattern.search(line):
1833 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221834
1835 # Per file checks
1836 if has_modified_logs:
1837 # Make sure the tag is using the "cr" prefix and is not too long
1838 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511839 tag_name = match.group('name') if match else None
1840 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221841 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511842 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221843 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511844 elif '.' in tag_name:
1845 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221846
1847 results = []
1848 if tag_decl_errors:
1849 results.append(output_api.PresubmitPromptWarning(
1850 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511851 '"private static final String TAG = "<package tag>".\n'
1852 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221853 tag_decl_errors))
1854
1855 if tag_length_errors:
1856 results.append(output_api.PresubmitError(
1857 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511858 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221859 tag_length_errors))
1860
1861 if tag_errors:
1862 results.append(output_api.PresubmitPromptWarning(
1863 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1864 tag_errors))
1865
dgn87d9fb62015-06-12 09:15:121866 if util_log_errors:
dgn4401aa52015-04-29 16:26:171867 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121868 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1869 util_log_errors))
1870
dgn38736db2015-09-18 19:20:511871 if tag_with_dot_errors:
1872 results.append(output_api.PresubmitPromptWarning(
1873 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1874 tag_with_dot_errors))
1875
dgn4401aa52015-04-29 16:26:171876 return results
1877
1878
yolandyan45001472016-12-21 21:12:421879def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1880 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1881 deprecated_annotation_import_pattern = input_api.re.compile(
1882 r'^import android\.test\.suitebuilder\.annotation\..*;',
1883 input_api.re.MULTILINE)
1884 sources = lambda x: input_api.FilterSourceFile(
1885 x, white_list=(r'.*\.java$',), black_list=None)
1886 errors = []
1887 for f in input_api.AffectedFiles(sources):
1888 for line_num, line in f.ChangedContents():
1889 if deprecated_annotation_import_pattern.search(line):
1890 errors.append("%s:%d" % (f.LocalPath(), line_num))
1891
1892 results = []
1893 if errors:
1894 results.append(output_api.PresubmitError(
1895 'Annotations in android.test.suitebuilder.annotation have been'
1896 ' deprecated since API level 24. Please use android.support.test.filters'
1897 ' from //third_party/android_support_test_runner:runner_java instead.'
1898 ' Contact [email protected] if you have any questions.', errors))
1899 return results
1900
1901
agrieve7b6479d82015-10-07 14:24:221902def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1903 """Checks if MDPI assets are placed in a correct directory."""
1904 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1905 ('/res/drawable/' in f.LocalPath() or
1906 '/res/drawable-ldrtl/' in f.LocalPath()))
1907 errors = []
1908 for f in input_api.AffectedFiles(include_deletes=False,
1909 file_filter=file_filter):
1910 errors.append(' %s' % f.LocalPath())
1911
1912 results = []
1913 if errors:
1914 results.append(output_api.PresubmitError(
1915 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1916 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1917 '/res/drawable-ldrtl/.\n'
1918 'Contact [email protected] if you have questions.', errors))
1919 return results
1920
1921
agrievef32bcc72016-04-04 14:57:401922class PydepsChecker(object):
1923 def __init__(self, input_api, pydeps_files):
1924 self._file_cache = {}
1925 self._input_api = input_api
1926 self._pydeps_files = pydeps_files
1927
1928 def _LoadFile(self, path):
1929 """Returns the list of paths within a .pydeps file relative to //."""
1930 if path not in self._file_cache:
1931 with open(path) as f:
1932 self._file_cache[path] = f.read()
1933 return self._file_cache[path]
1934
1935 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1936 """Returns an interable of paths within the .pydep, relativized to //."""
1937 os_path = self._input_api.os_path
1938 pydeps_dir = os_path.dirname(pydeps_path)
1939 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1940 if not l.startswith('*'))
1941 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1942
1943 def _CreateFilesToPydepsMap(self):
1944 """Returns a map of local_path -> list_of_pydeps."""
1945 ret = {}
1946 for pydep_local_path in self._pydeps_files:
1947 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1948 ret.setdefault(path, []).append(pydep_local_path)
1949 return ret
1950
1951 def ComputeAffectedPydeps(self):
1952 """Returns an iterable of .pydeps files that might need regenerating."""
1953 affected_pydeps = set()
1954 file_to_pydeps_map = None
1955 for f in self._input_api.AffectedFiles(include_deletes=True):
1956 local_path = f.LocalPath()
1957 if local_path == 'DEPS':
1958 return self._pydeps_files
1959 elif local_path.endswith('.pydeps'):
1960 if local_path in self._pydeps_files:
1961 affected_pydeps.add(local_path)
1962 elif local_path.endswith('.py'):
1963 if file_to_pydeps_map is None:
1964 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1965 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1966 return affected_pydeps
1967
1968 def DetermineIfStale(self, pydeps_path):
1969 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411970 import difflib
agrievef32bcc72016-04-04 14:57:401971 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1972 cmd = old_pydeps_data[1][1:].strip()
1973 new_pydeps_data = self._input_api.subprocess.check_output(
1974 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411975 old_contents = old_pydeps_data[2:]
1976 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401977 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411978 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401979
1980
1981def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1982 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001983 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281984 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1985 # Mac, so skip it on other platforms.
1986 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001987 return []
agrievef32bcc72016-04-04 14:57:401988 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1989 is_android = input_api.os_path.exists('third_party/android_tools')
1990 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1991 results = []
1992 # First, check for new / deleted .pydeps.
1993 for f in input_api.AffectedFiles(include_deletes=True):
1994 if f.LocalPath().endswith('.pydeps'):
1995 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1996 results.append(output_api.PresubmitError(
1997 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1998 'remove %s' % f.LocalPath()))
1999 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2000 results.append(output_api.PresubmitError(
2001 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2002 'include %s' % f.LocalPath()))
2003
2004 if results:
2005 return results
2006
2007 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2008
2009 for pydep_path in checker.ComputeAffectedPydeps():
2010 try:
phajdan.jr0d9878552016-11-04 10:49:412011 result = checker.DetermineIfStale(pydep_path)
2012 if result:
2013 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402014 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412015 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2016 'To regenerate, run:\n\n %s' %
2017 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402018 except input_api.subprocess.CalledProcessError as error:
2019 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2020 long_text=error.output)]
2021
2022 return results
2023
2024
glidere61efad2015-02-18 17:39:432025def _CheckSingletonInHeaders(input_api, output_api):
2026 """Checks to make sure no header files have |Singleton<|."""
2027 def FileFilter(affected_file):
2028 # It's ok for base/memory/singleton.h to have |Singleton<|.
2029 black_list = (_EXCLUDED_PATHS +
2030 input_api.DEFAULT_BLACK_LIST +
2031 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
2032 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2033
sergeyu34d21222015-09-16 00:11:442034 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432035 files = []
2036 for f in input_api.AffectedSourceFiles(FileFilter):
2037 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2038 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2039 contents = input_api.ReadFile(f)
2040 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242041 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432042 pattern.search(line)):
2043 files.append(f)
2044 break
2045
2046 if files:
yolandyandaabc6d2016-04-18 18:29:392047 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442048 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432049 'Please move them to an appropriate source file so that the ' +
2050 'template gets instantiated in a single compilation unit.',
2051 files) ]
2052 return []
2053
2054
[email protected]fd20b902014-05-09 02:14:532055_DEPRECATED_CSS = [
2056 # Values
2057 ( "-webkit-box", "flex" ),
2058 ( "-webkit-inline-box", "inline-flex" ),
2059 ( "-webkit-flex", "flex" ),
2060 ( "-webkit-inline-flex", "inline-flex" ),
2061 ( "-webkit-min-content", "min-content" ),
2062 ( "-webkit-max-content", "max-content" ),
2063
2064 # Properties
2065 ( "-webkit-background-clip", "background-clip" ),
2066 ( "-webkit-background-origin", "background-origin" ),
2067 ( "-webkit-background-size", "background-size" ),
2068 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442069 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532070
2071 # Functions
2072 ( "-webkit-gradient", "gradient" ),
2073 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2074 ( "-webkit-linear-gradient", "linear-gradient" ),
2075 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2076 ( "-webkit-radial-gradient", "radial-gradient" ),
2077 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2078]
2079
dbeam1ec68ac2016-12-15 05:22:242080def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532081 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252082 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342083 documentation and iOS CSS for dom distiller
2084 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252085 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532086 results = []
dbeam070cfe62014-10-22 06:44:022087 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252088 black_list = (_EXCLUDED_PATHS +
2089 _TEST_CODE_EXCLUDED_PATHS +
2090 input_api.DEFAULT_BLACK_LIST +
2091 (r"^chrome/common/extensions/docs",
2092 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342093 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052094 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442095 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252096 r"^native_client_sdk"))
2097 file_filter = lambda f: input_api.FilterSourceFile(
2098 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532099 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2100 for line_num, line in fpath.ChangedContents():
2101 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022102 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532103 results.append(output_api.PresubmitError(
2104 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2105 (fpath.LocalPath(), line_num, deprecated_value, value)))
2106 return results
2107
mohan.reddyf21db962014-10-16 12:26:472108
dbeam070cfe62014-10-22 06:44:022109_DEPRECATED_JS = [
2110 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2111 ( "__defineGetter__", "Object.defineProperty" ),
2112 ( "__defineSetter__", "Object.defineProperty" ),
2113]
2114
dbeam1ec68ac2016-12-15 05:22:242115def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022116 """Make sure that we don't use deprecated JS in Chrome code."""
2117 results = []
2118 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2119 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2120 input_api.DEFAULT_BLACK_LIST)
2121 file_filter = lambda f: input_api.FilterSourceFile(
2122 f, white_list=file_inclusion_pattern, black_list=black_list)
2123 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2124 for lnum, line in fpath.ChangedContents():
2125 for (deprecated, replacement) in _DEPRECATED_JS:
2126 if deprecated in line:
2127 results.append(output_api.PresubmitError(
2128 "%s:%d: Use of deprecated JS %s, use %s instead" %
2129 (fpath.LocalPath(), lnum, deprecated, replacement)))
2130 return results
2131
2132
dbeam1ec68ac2016-12-15 05:22:242133def _CheckForRiskyJsFeatures(input_api, output_api):
2134 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2135 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2136
2137 arrow_lines = []
2138 for f in input_api.AffectedFiles(file_filter=file_filter):
2139 for lnum, line in f.ChangedContents():
2140 if ' => ' in line:
2141 arrow_lines.append((f.LocalPath(), lnum))
2142
2143 if not arrow_lines:
2144 return []
2145
2146 return [output_api.PresubmitPromptWarning("""
2147Use of => operator detected in:
2148%s
2149Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2150https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2151""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2152
2153
rlanday6802cf632017-05-30 17:48:362154def _CheckForRelativeIncludes(input_api, output_api):
2155 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2156 import sys
2157 original_sys_path = sys.path
2158 try:
2159 sys.path = sys.path + [input_api.os_path.join(
2160 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2161 from cpp_checker import CppChecker
2162 finally:
2163 # Restore sys.path to what it was before.
2164 sys.path = original_sys_path
2165
2166 bad_files = {}
2167 for f in input_api.AffectedFiles(include_deletes=False):
2168 if (f.LocalPath().startswith('third_party') and
2169 not f.LocalPath().startswith('third_party/WebKit') and
2170 not f.LocalPath().startswith('third_party\\WebKit')):
2171 continue
2172
2173 if not CppChecker.IsCppFile(f.LocalPath()):
2174 continue
2175
2176 relative_includes = [line for line_num, line in f.ChangedContents()
2177 if "#include" in line and "../" in line]
2178 if not relative_includes:
2179 continue
2180 bad_files[f.LocalPath()] = relative_includes
2181
2182 if not bad_files:
2183 return []
2184
2185 error_descriptions = []
2186 for file_path, bad_lines in bad_files.iteritems():
2187 error_description = file_path
2188 for line in bad_lines:
2189 error_description += '\n ' + line
2190 error_descriptions.append(error_description)
2191
2192 results = []
2193 results.append(output_api.PresubmitError(
2194 'You added one or more relative #include paths (including "../").\n'
2195 'These shouldn\'t be used because they can be used to include headers\n'
2196 'from code that\'s not correctly specified as a dependency in the\n'
2197 'relevant BUILD.gn file(s).',
2198 error_descriptions))
2199
2200 return results
2201
dgnaa68d5e2015-06-10 10:08:222202def _AndroidSpecificOnUploadChecks(input_api, output_api):
2203 """Groups checks that target android code."""
2204 results = []
dgnaa68d5e2015-06-10 10:08:222205 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222206 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292207 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422208 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222209 return results
2210
2211
[email protected]22c9bd72011-03-27 16:47:392212def _CommonChecks(input_api, output_api):
2213 """Checks common to both upload and commit."""
2214 results = []
2215 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382216 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542217 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582218 results.extend(
2219 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192220 results.extend(
[email protected]760deea2013-12-10 19:33:492221 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542222 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182223 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522224 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222225 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442226 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592227 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062228 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122229 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182230 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222231 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302232 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492233 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272234 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032235 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492236 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442237 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272238 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542239 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442240 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392241 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552242 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042243 results.extend(
2244 input_api.canned_checks.CheckChangeHasNoTabs(
2245 input_api,
2246 output_api,
2247 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402248 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162249 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592250 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082251 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242252 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2253 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472254 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042255 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232256 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432257 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402258 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152259 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172260 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502261 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242262 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362263 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242264
2265 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2266 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2267 input_api, output_api,
2268 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382269 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392270 return results
[email protected]1f7b4172010-01-28 01:17:342271
[email protected]b337cb5b2011-01-23 21:24:052272
[email protected]b8079ae4a2012-12-05 19:56:492273def _CheckPatchFiles(input_api, output_api):
2274 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2275 if f.LocalPath().endswith(('.orig', '.rej'))]
2276 if problems:
2277 return [output_api.PresubmitError(
2278 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032279 else:
2280 return []
[email protected]b8079ae4a2012-12-05 19:56:492281
2282
[email protected]b00342e7f2013-03-26 16:21:542283def _DidYouMeanOSMacro(bad_macro):
2284 try:
2285 return {'A': 'OS_ANDROID',
2286 'B': 'OS_BSD',
2287 'C': 'OS_CHROMEOS',
2288 'F': 'OS_FREEBSD',
2289 'L': 'OS_LINUX',
2290 'M': 'OS_MACOSX',
2291 'N': 'OS_NACL',
2292 'O': 'OS_OPENBSD',
2293 'P': 'OS_POSIX',
2294 'S': 'OS_SOLARIS',
2295 'W': 'OS_WIN'}[bad_macro[3].upper()]
2296 except KeyError:
2297 return ''
2298
2299
2300def _CheckForInvalidOSMacrosInFile(input_api, f):
2301 """Check for sensible looking, totally invalid OS macros."""
2302 preprocessor_statement = input_api.re.compile(r'^\s*#')
2303 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2304 results = []
2305 for lnum, line in f.ChangedContents():
2306 if preprocessor_statement.search(line):
2307 for match in os_macro.finditer(line):
2308 if not match.group(1) in _VALID_OS_MACROS:
2309 good = _DidYouMeanOSMacro(match.group(1))
2310 did_you_mean = ' (did you mean %s?)' % good if good else ''
2311 results.append(' %s:%d %s%s' % (f.LocalPath(),
2312 lnum,
2313 match.group(1),
2314 did_you_mean))
2315 return results
2316
2317
2318def _CheckForInvalidOSMacros(input_api, output_api):
2319 """Check all affected files for invalid OS macros."""
2320 bad_macros = []
2321 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472322 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542323 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2324
2325 if not bad_macros:
2326 return []
2327
2328 return [output_api.PresubmitError(
2329 'Possibly invalid OS macro[s] found. Please fix your code\n'
2330 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2331
lliabraa35bab3932014-10-01 12:16:442332
2333def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2334 """Check all affected files for invalid "if defined" macros."""
2335 ALWAYS_DEFINED_MACROS = (
2336 "TARGET_CPU_PPC",
2337 "TARGET_CPU_PPC64",
2338 "TARGET_CPU_68K",
2339 "TARGET_CPU_X86",
2340 "TARGET_CPU_ARM",
2341 "TARGET_CPU_MIPS",
2342 "TARGET_CPU_SPARC",
2343 "TARGET_CPU_ALPHA",
2344 "TARGET_IPHONE_SIMULATOR",
2345 "TARGET_OS_EMBEDDED",
2346 "TARGET_OS_IPHONE",
2347 "TARGET_OS_MAC",
2348 "TARGET_OS_UNIX",
2349 "TARGET_OS_WIN32",
2350 )
2351 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2352 results = []
2353 for lnum, line in f.ChangedContents():
2354 for match in ifdef_macro.finditer(line):
2355 if match.group(1) in ALWAYS_DEFINED_MACROS:
2356 always_defined = ' %s is always defined. ' % match.group(1)
2357 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2358 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2359 lnum,
2360 always_defined,
2361 did_you_mean))
2362 return results
2363
2364
2365def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2366 """Check all affected files for invalid "if defined" macros."""
2367 bad_macros = []
2368 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212369 if f.LocalPath().startswith('third_party/sqlite/'):
2370 continue
lliabraa35bab3932014-10-01 12:16:442371 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2372 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2373
2374 if not bad_macros:
2375 return []
2376
2377 return [output_api.PresubmitError(
2378 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2379 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2380 bad_macros)]
2381
2382
mlamouria82272622014-09-16 18:45:042383def _CheckForIPCRules(input_api, output_api):
2384 """Check for same IPC rules described in
2385 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2386 """
2387 base_pattern = r'IPC_ENUM_TRAITS\('
2388 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2389 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2390
2391 problems = []
2392 for f in input_api.AffectedSourceFiles(None):
2393 local_path = f.LocalPath()
2394 if not local_path.endswith('.h'):
2395 continue
2396 for line_number, line in f.ChangedContents():
2397 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2398 problems.append(
2399 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2400
2401 if problems:
2402 return [output_api.PresubmitPromptWarning(
2403 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2404 else:
2405 return []
2406
[email protected]b00342e7f2013-03-26 16:21:542407
mostynbb639aca52015-01-07 20:31:232408def _CheckForWindowsLineEndings(input_api, output_api):
2409 """Check source code and known ascii text files for Windows style line
2410 endings.
2411 """
earthdok1b5e0ee2015-03-10 15:19:102412 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232413
2414 file_inclusion_pattern = (
2415 known_text_files,
2416 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2417 )
2418
2419 filter = lambda f: input_api.FilterSourceFile(
2420 f, white_list=file_inclusion_pattern, black_list=None)
2421 files = [f.LocalPath() for f in
2422 input_api.AffectedSourceFiles(filter)]
2423
2424 problems = []
2425
2426 for file in files:
2427 fp = open(file, 'r')
2428 for line in fp:
2429 if line.endswith('\r\n'):
2430 problems.append(file)
2431 break
2432 fp.close()
2433
2434 if problems:
2435 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2436 'these files to contain Windows style line endings?\n' +
2437 '\n'.join(problems))]
2438
2439 return []
2440
2441
pastarmovj89f7ee12016-09-20 14:58:132442def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2443 lint_filters=None, verbose_level=None):
2444 """Checks that all source files use SYSLOG properly."""
2445 syslog_files = []
2446 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562447 for line_number, line in f.ChangedContents():
2448 if 'SYSLOG' in line:
2449 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2450
pastarmovj89f7ee12016-09-20 14:58:132451 if syslog_files:
2452 return [output_api.PresubmitPromptWarning(
2453 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2454 ' calls.\nFiles to check:\n', items=syslog_files)]
2455 return []
2456
2457
[email protected]1f7b4172010-01-28 01:17:342458def CheckChangeOnUpload(input_api, output_api):
2459 results = []
2460 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472461 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282462 results.extend(
jam93a6ee792017-02-08 23:59:222463 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192464 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222465 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132466 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162467 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542468 return results
[email protected]ca8d19842009-02-19 16:33:122469
2470
[email protected]1bfb8322014-04-23 01:02:412471def GetTryServerMasterForBot(bot):
2472 """Returns the Try Server master for the given bot.
2473
[email protected]0bb112362014-07-26 04:38:322474 It tries to guess the master from the bot name, but may still fail
2475 and return None. There is no longer a default master.
2476 """
2477 # Potentially ambiguous bot names are listed explicitly.
2478 master_map = {
tandriie5587792016-07-14 00:34:502479 'chromium_presubmit': 'master.tryserver.chromium.linux',
2480 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412481 }
[email protected]0bb112362014-07-26 04:38:322482 master = master_map.get(bot)
2483 if not master:
wnwen4fbaab82016-05-25 12:54:362484 if 'android' in bot:
tandriie5587792016-07-14 00:34:502485 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362486 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502487 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322488 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502489 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322490 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502491 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322492 return master
[email protected]1bfb8322014-04-23 01:02:412493
2494
Paweł Hajdan, Jr55083782014-12-19 20:32:562495def GetDefaultTryConfigs(bots):
2496 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012497 """
2498
Paweł Hajdan, Jr55083782014-12-19 20:32:562499 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412500
2501 # Build up the mapping from tryserver master to bot/test.
2502 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562503 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412504 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2505 return out
[email protected]38c6a512013-12-18 23:48:012506
2507
[email protected]ca8d19842009-02-19 16:33:122508def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542509 results = []
[email protected]1f7b4172010-01-28 01:17:342510 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542511 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272512 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342513 input_api,
2514 output_api,
[email protected]2fdd1f362013-01-16 03:56:032515 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272516
jam93a6ee792017-02-08 23:59:222517 results.extend(
2518 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542519 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2520 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412521 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2522 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542523 return results