blob: a32035426b498e53b62f927050b27b0f64f925ef [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$",
philipj3f9d5bde2014-08-28 14:09:09207 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49208 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
209 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25210 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41211 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
212 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25213 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48214 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
215 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01216 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25217 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
218 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
219 r"embedded_test_server\.cc$",
220 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
221 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54222 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16223 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53224 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
225 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45226 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
227 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
228 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
229 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
230 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49231 ),
[email protected]23e6cbc2012-06-16 18:51:20232 ),
[email protected]52657f62013-05-20 05:30:31233 (
tomhudsone2c14d552016-05-26 17:07:46234 'setMatrixClip',
235 (
236 'Overriding setMatrixClip() is prohibited; ',
237 'the base function is deprecated. ',
238 ),
239 True,
240 (),
241 ),
242 (
[email protected]52657f62013-05-20 05:30:31243 'SkRefPtr',
244 (
245 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22246 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31247 ),
248 True,
249 (),
250 ),
251 (
252 'SkAutoRef',
253 (
254 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22255 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31256 ),
257 True,
258 (),
259 ),
260 (
261 'SkAutoTUnref',
262 (
263 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22264 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31265 ),
266 True,
267 (),
268 ),
269 (
270 'SkAutoUnref',
271 (
272 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
273 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22274 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31275 ),
276 True,
277 (),
278 ),
[email protected]d89eec82013-12-03 14:10:59279 (
280 r'/HANDLE_EINTR\(.*close',
281 (
282 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
283 'descriptor will be closed, and it is incorrect to retry the close.',
284 'Either call close directly and ignore its return value, or wrap close',
285 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
286 ),
287 True,
288 (),
289 ),
290 (
291 r'/IGNORE_EINTR\((?!.*close)',
292 (
293 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
294 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
295 ),
296 True,
297 (
298 # Files that #define IGNORE_EINTR.
299 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
300 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
301 ),
302 ),
[email protected]ec5b3f02014-04-04 18:43:43303 (
304 r'/v8::Extension\(',
305 (
306 'Do not introduce new v8::Extensions into the code base, use',
307 'gin::Wrappable instead. See http://crbug.com/334679',
308 ),
309 True,
[email protected]f55c90ee62014-04-12 00:50:03310 (
joaodasilva718f87672014-08-30 09:25:49311 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03312 ),
[email protected]ec5b3f02014-04-04 18:43:43313 ),
skyostilf9469f72015-04-20 10:38:52314 (
jame2d1a952016-04-02 00:27:10315 '#pragma comment(lib,',
316 (
317 'Specify libraries to link with in build files and not in the source.',
318 ),
319 True,
320 (),
321 ),
fdorayc4ac18d2017-05-01 21:39:59322 (
323 'BrowserThread::GetBlockingPool',
324 (
325 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
326 'mapping between both APIs in content/public/browser/browser_thread.h.',
327 'For questions, contact base/task_scheduler/OWNERS.',
328 ),
329 True,
330 (),
331 ),
gabd52c912a2017-05-11 04:15:59332 (
333 'base::NonThreadSafe',
334 (
335 'base::NonThreadSafe is deprecated.',
336 ),
337 True,
338 (),
339 ),
340 (
341 'base::SequenceChecker',
342 (
343 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
344 ),
345 False,
346 (),
347 ),
348 (
349 'base::ThreadChecker',
350 (
351 'Consider using THREAD_CHECKER macros instead of the class directly.',
352 ),
353 False,
354 (),
355 ),
[email protected]127f18ec2012-06-16 05:05:59356)
357
wnwenbdc444e2016-05-25 13:44:15358
mlamouria82272622014-09-16 18:45:04359_IPC_ENUM_TRAITS_DEPRECATED = (
360 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
361 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
362
[email protected]127f18ec2012-06-16 05:05:59363
[email protected]b00342e7f2013-03-26 16:21:54364_VALID_OS_MACROS = (
365 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08366 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54367 'OS_ANDROID',
368 'OS_BSD',
369 'OS_CAT', # For testing.
370 'OS_CHROMEOS',
371 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37372 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54373 'OS_IOS',
374 'OS_LINUX',
375 'OS_MACOSX',
376 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21377 'OS_NACL_NONSFI',
378 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12379 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54380 'OS_OPENBSD',
381 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37382 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54383 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54384 'OS_WIN',
385)
386
387
agrievef32bcc72016-04-04 14:57:40388_ANDROID_SPECIFIC_PYDEPS_FILES = [
389 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04390 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58391 'build/secondary/third_party/android_platform/'
392 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19393 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40394]
395
wnwenbdc444e2016-05-25 13:44:15396
agrievef32bcc72016-04-04 14:57:40397_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40398]
399
wnwenbdc444e2016-05-25 13:44:15400
agrievef32bcc72016-04-04 14:57:40401_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
402
403
[email protected]55459852011-08-10 15:17:19404def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
405 """Attempts to prevent use of functions intended only for testing in
406 non-testing code. For now this is just a best-effort implementation
407 that ignores header files and may have some false positives. A
408 better implementation would probably need a proper C++ parser.
409 """
410 # We only scan .cc files and the like, as the declaration of
411 # for-testing functions in header files are hard to distinguish from
412 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44413 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19414
jochenc0d4808c2015-07-27 09:25:42415 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19416 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09417 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19418 exclusion_pattern = input_api.re.compile(
419 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
420 base_function_pattern, base_function_pattern))
421
422 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44423 black_list = (_EXCLUDED_PATHS +
424 _TEST_CODE_EXCLUDED_PATHS +
425 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19426 return input_api.FilterSourceFile(
427 affected_file,
428 white_list=(file_inclusion_pattern, ),
429 black_list=black_list)
430
431 problems = []
432 for f in input_api.AffectedSourceFiles(FilterFile):
433 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24434 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03435 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46436 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03437 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19438 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03439 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19440
441 if problems:
[email protected]f7051d52013-04-02 18:31:42442 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03443 else:
444 return []
[email protected]55459852011-08-10 15:17:19445
446
[email protected]10689ca2011-09-02 02:31:54447def _CheckNoIOStreamInHeaders(input_api, output_api):
448 """Checks to make sure no .h files include <iostream>."""
449 files = []
450 pattern = input_api.re.compile(r'^#include\s*<iostream>',
451 input_api.re.MULTILINE)
452 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
453 if not f.LocalPath().endswith('.h'):
454 continue
455 contents = input_api.ReadFile(f)
456 if pattern.search(contents):
457 files.append(f)
458
459 if len(files):
yolandyandaabc6d2016-04-18 18:29:39460 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06461 'Do not #include <iostream> in header files, since it inserts static '
462 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54463 '#include <ostream>. See http://crbug.com/94794',
464 files) ]
465 return []
466
467
[email protected]72df4e782012-06-21 16:28:18468def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52469 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18470 problems = []
471 for f in input_api.AffectedFiles():
472 if (not f.LocalPath().endswith(('.cc', '.mm'))):
473 continue
474
475 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04476 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18477 problems.append(' %s:%d' % (f.LocalPath(), line_num))
478
479 if not problems:
480 return []
481 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
482 '\n'.join(problems))]
483
484
danakj61c1aa22015-10-26 19:55:52485def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57486 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52487 errors = []
488 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
489 input_api.re.MULTILINE)
490 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
491 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
492 continue
493 for lnum, line in f.ChangedContents():
494 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17495 errors.append(output_api.PresubmitError(
496 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57497 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17498 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52499 return errors
500
501
mcasasb7440c282015-02-04 14:52:19502def _FindHistogramNameInLine(histogram_name, line):
503 """Tries to find a histogram name or prefix in a line."""
504 if not "affected-histogram" in line:
505 return histogram_name in line
506 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
507 # the histogram_name.
508 if not '"' in line:
509 return False
510 histogram_prefix = line.split('\"')[1]
511 return histogram_prefix in histogram_name
512
513
514def _CheckUmaHistogramChanges(input_api, output_api):
515 """Check that UMA histogram names in touched lines can still be found in other
516 lines of the patch or in histograms.xml. Note that this check would not catch
517 the reverse: changes in histograms.xml not matched in the code itself."""
518 touched_histograms = []
519 histograms_xml_modifications = []
520 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
521 for f in input_api.AffectedFiles():
522 # If histograms.xml itself is modified, keep the modified lines for later.
523 if f.LocalPath().endswith(('histograms.xml')):
524 histograms_xml_modifications = f.ChangedContents()
525 continue
526 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
527 continue
528 for line_num, line in f.ChangedContents():
529 found = pattern.search(line)
530 if found:
531 touched_histograms.append([found.group(1), f, line_num])
532
533 # Search for the touched histogram names in the local modifications to
534 # histograms.xml, and, if not found, on the base histograms.xml file.
535 unmatched_histograms = []
536 for histogram_info in touched_histograms:
537 histogram_name_found = False
538 for line_num, line in histograms_xml_modifications:
539 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
540 if histogram_name_found:
541 break
542 if not histogram_name_found:
543 unmatched_histograms.append(histogram_info)
544
eromanb90c82e7e32015-04-01 15:13:49545 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19546 problems = []
547 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49548 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19549 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45550 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19551 histogram_name_found = False
552 for line in histograms_xml:
553 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
554 if histogram_name_found:
555 break
556 if not histogram_name_found:
557 problems.append(' [%s:%d] %s' %
558 (f.LocalPath(), line_num, histogram_name))
559
560 if not problems:
561 return []
562 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
563 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49564 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19565
wnwenbdc444e2016-05-25 13:44:15566
yolandyandaabc6d2016-04-18 18:29:39567def _CheckFlakyTestUsage(input_api, output_api):
568 """Check that FlakyTest annotation is our own instead of the android one"""
569 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
570 files = []
571 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
572 if f.LocalPath().endswith('Test.java'):
573 if pattern.search(input_api.ReadFile(f)):
574 files.append(f)
575 if len(files):
576 return [output_api.PresubmitError(
577 'Use org.chromium.base.test.util.FlakyTest instead of '
578 'android.test.FlakyTest',
579 files)]
580 return []
mcasasb7440c282015-02-04 14:52:19581
wnwenbdc444e2016-05-25 13:44:15582
[email protected]8ea5d4b2011-09-13 21:49:22583def _CheckNoNewWStrings(input_api, output_api):
584 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27585 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22586 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20587 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57588 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34589 '/win/' in f.LocalPath() or
590 'chrome_elf' in f.LocalPath() or
591 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20592 continue
[email protected]8ea5d4b2011-09-13 21:49:22593
[email protected]a11dbe9b2012-08-07 01:32:58594 allowWString = False
[email protected]b5c24292011-11-28 14:38:20595 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58596 if 'presubmit: allow wstring' in line:
597 allowWString = True
598 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27599 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58600 allowWString = False
601 else:
602 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22603
[email protected]55463aa62011-10-12 00:48:27604 if not problems:
605 return []
606 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58607 ' If you are calling a cross-platform API that accepts a wstring, '
608 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27609 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22610
611
[email protected]2a8ac9c2011-10-19 17:20:44612def _CheckNoDEPSGIT(input_api, output_api):
613 """Make sure .DEPS.git is never modified manually."""
614 if any(f.LocalPath().endswith('.DEPS.git') for f in
615 input_api.AffectedFiles()):
616 return [output_api.PresubmitError(
617 'Never commit changes to .DEPS.git. This file is maintained by an\n'
618 'automated system based on what\'s in DEPS and your changes will be\n'
619 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34620 '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:44621 'for more information')]
622 return []
623
624
tandriief664692014-09-23 14:51:47625def _CheckValidHostsInDEPS(input_api, output_api):
626 """Checks that DEPS file deps are from allowed_hosts."""
627 # Run only if DEPS file has been modified to annoy fewer bystanders.
628 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
629 return []
630 # Outsource work to gclient verify
631 try:
632 input_api.subprocess.check_output(['gclient', 'verify'])
633 return []
634 except input_api.subprocess.CalledProcessError, error:
635 return [output_api.PresubmitError(
636 'DEPS file must have only git dependencies.',
637 long_text=error.output)]
638
639
[email protected]127f18ec2012-06-16 05:05:59640def _CheckNoBannedFunctions(input_api, output_api):
641 """Make sure that banned functions are not used."""
642 warnings = []
643 errors = []
644
wnwenbdc444e2016-05-25 13:44:15645 def IsBlacklisted(affected_file, blacklist):
646 local_path = affected_file.LocalPath()
647 for item in blacklist:
648 if input_api.re.match(item, local_path):
649 return True
650 return False
651
652 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
653 matched = False
654 if func_name[0:1] == '/':
655 regex = func_name[1:]
656 if input_api.re.search(regex, line):
657 matched = True
658 elif func_name in line:
dchenge07de812016-06-20 19:27:17659 matched = True
wnwenbdc444e2016-05-25 13:44:15660 if matched:
dchenge07de812016-06-20 19:27:17661 problems = warnings
wnwenbdc444e2016-05-25 13:44:15662 if error:
dchenge07de812016-06-20 19:27:17663 problems = errors
wnwenbdc444e2016-05-25 13:44:15664 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
665 for message_line in message:
666 problems.append(' %s' % message_line)
667
[email protected]127f18ec2012-06-16 05:05:59668 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
669 for f in input_api.AffectedFiles(file_filter=file_filter):
670 for line_num, line in f.ChangedContents():
671 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15672 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59673
674 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
675 for f in input_api.AffectedFiles(file_filter=file_filter):
676 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49677 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49678 if IsBlacklisted(f, excluded_paths):
679 continue
wnwenbdc444e2016-05-25 13:44:15680 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59681
682 result = []
683 if (warnings):
684 result.append(output_api.PresubmitPromptWarning(
685 'Banned functions were used.\n' + '\n'.join(warnings)))
686 if (errors):
687 result.append(output_api.PresubmitError(
688 'Banned functions were used.\n' + '\n'.join(errors)))
689 return result
690
691
[email protected]6c063c62012-07-11 19:11:06692def _CheckNoPragmaOnce(input_api, output_api):
693 """Make sure that banned functions are not used."""
694 files = []
695 pattern = input_api.re.compile(r'^#pragma\s+once',
696 input_api.re.MULTILINE)
697 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
698 if not f.LocalPath().endswith('.h'):
699 continue
700 contents = input_api.ReadFile(f)
701 if pattern.search(contents):
702 files.append(f)
703
704 if files:
705 return [output_api.PresubmitError(
706 'Do not use #pragma once in header files.\n'
707 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
708 files)]
709 return []
710
[email protected]127f18ec2012-06-16 05:05:59711
[email protected]e7479052012-09-19 00:26:12712def _CheckNoTrinaryTrueFalse(input_api, output_api):
713 """Checks to make sure we don't introduce use of foo ? true : false."""
714 problems = []
715 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
716 for f in input_api.AffectedFiles():
717 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
718 continue
719
720 for line_num, line in f.ChangedContents():
721 if pattern.match(line):
722 problems.append(' %s:%d' % (f.LocalPath(), line_num))
723
724 if not problems:
725 return []
726 return [output_api.PresubmitPromptWarning(
727 'Please consider avoiding the "? true : false" pattern if possible.\n' +
728 '\n'.join(problems))]
729
730
[email protected]55f9f382012-07-31 11:02:18731def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28732 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18733 change. Breaking - rules is an error, breaking ! rules is a
734 warning.
735 """
mohan.reddyf21db962014-10-16 12:26:47736 import sys
[email protected]55f9f382012-07-31 11:02:18737 # We need to wait until we have an input_api object and use this
738 # roundabout construct to import checkdeps because this file is
739 # eval-ed and thus doesn't have __file__.
740 original_sys_path = sys.path
741 try:
742 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47743 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18744 import checkdeps
745 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28746 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18747 from rules import Rule
748 finally:
749 # Restore sys.path to what it was before.
750 sys.path = original_sys_path
751
752 added_includes = []
rhalavati08acd232017-04-03 07:23:28753 added_imports = []
[email protected]55f9f382012-07-31 11:02:18754 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28755 if CppChecker.IsCppFile(f.LocalPath()):
756 changed_lines = [line for line_num, line in f.ChangedContents()]
757 added_includes.append([f.LocalPath(), changed_lines])
758 elif ProtoChecker.IsProtoFile(f.LocalPath()):
759 changed_lines = [line for line_num, line in f.ChangedContents()]
760 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18761
[email protected]26385172013-05-09 23:11:35762 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18763
764 error_descriptions = []
765 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28766 error_subjects = set()
767 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18768 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
769 added_includes):
770 description_with_path = '%s\n %s' % (path, rule_description)
771 if rule_type == Rule.DISALLOW:
772 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28773 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18774 else:
775 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28776 warning_subjects.add("#includes")
777
778 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
779 added_imports):
780 description_with_path = '%s\n %s' % (path, rule_description)
781 if rule_type == Rule.DISALLOW:
782 error_descriptions.append(description_with_path)
783 error_subjects.add("imports")
784 else:
785 warning_descriptions.append(description_with_path)
786 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18787
788 results = []
789 if error_descriptions:
790 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28791 'You added one or more %s that violate checkdeps rules.'
792 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18793 error_descriptions))
794 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42795 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28796 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18797 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28798 '%s? See relevant DEPS file(s) for details and contacts.' %
799 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18800 warning_descriptions))
801 return results
802
803
[email protected]fbcafe5a2012-08-08 15:31:22804def _CheckFilePermissions(input_api, output_api):
805 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15806 if input_api.platform == 'win32':
807 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29808 checkperms_tool = input_api.os_path.join(
809 input_api.PresubmitLocalPath(),
810 'tools', 'checkperms', 'checkperms.py')
811 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47812 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22813 for f in input_api.AffectedFiles():
814 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11815 try:
816 input_api.subprocess.check_output(args)
817 return []
818 except input_api.subprocess.CalledProcessError as error:
819 return [output_api.PresubmitError(
820 'checkperms.py failed:',
821 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22822
823
robertocn832f5992017-01-04 19:01:30824def _CheckTeamTags(input_api, output_api):
825 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
826 checkteamtags_tool = input_api.os_path.join(
827 input_api.PresubmitLocalPath(),
828 'tools', 'checkteamtags', 'checkteamtags.py')
829 args = [input_api.python_executable, checkteamtags_tool,
830 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22831 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30832 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
833 'OWNERS']
834 try:
835 if files:
836 input_api.subprocess.check_output(args + files)
837 return []
838 except input_api.subprocess.CalledProcessError as error:
839 return [output_api.PresubmitError(
840 'checkteamtags.py failed:',
841 long_text=error.output)]
842
843
[email protected]c8278b32012-10-30 20:35:49844def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
845 """Makes sure we don't include ui/aura/window_property.h
846 in header files.
847 """
848 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
849 errors = []
850 for f in input_api.AffectedFiles():
851 if not f.LocalPath().endswith('.h'):
852 continue
853 for line_num, line in f.ChangedContents():
854 if pattern.match(line):
855 errors.append(' %s:%d' % (f.LocalPath(), line_num))
856
857 results = []
858 if errors:
859 results.append(output_api.PresubmitError(
860 'Header files should not include ui/aura/window_property.h', errors))
861 return results
862
863
[email protected]cf9b78f2012-11-14 11:40:28864def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
865 """Checks that the lines in scope occur in the right order.
866
867 1. C system files in alphabetical order
868 2. C++ system files in alphabetical order
869 3. Project's .h files
870 """
871
872 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
873 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
874 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
875
876 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
877
878 state = C_SYSTEM_INCLUDES
879
880 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57881 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28882 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55883 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28884 for line_num, line in scope:
885 if c_system_include_pattern.match(line):
886 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55887 problem_linenums.append((line_num, previous_line_num,
888 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28889 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55890 problem_linenums.append((line_num, previous_line_num,
891 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28892 elif cpp_system_include_pattern.match(line):
893 if state == C_SYSTEM_INCLUDES:
894 state = CPP_SYSTEM_INCLUDES
895 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55896 problem_linenums.append((line_num, previous_line_num,
897 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28898 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55899 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28900 elif custom_include_pattern.match(line):
901 if state != CUSTOM_INCLUDES:
902 state = CUSTOM_INCLUDES
903 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55904 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28905 else:
brucedawson70fadb02015-06-30 17:47:55906 problem_linenums.append((line_num, previous_line_num,
907 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28908 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57909 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28910
911 warnings = []
brucedawson70fadb02015-06-30 17:47:55912 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57913 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55914 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28915 return warnings
916
917
[email protected]ac294a12012-12-06 16:38:43918def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28919 """Checks the #include order for the given file f."""
920
[email protected]2299dcf2012-11-15 19:56:24921 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30922 # Exclude the following includes from the check:
923 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
924 # specific order.
925 # 2) <atlbase.h>, "build/build_config.h"
926 excluded_include_pattern = input_api.re.compile(
927 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24928 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33929 # Match the final or penultimate token if it is xxxtest so we can ignore it
930 # when considering the special first include.
931 test_file_tag_pattern = input_api.re.compile(
932 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11933 if_pattern = input_api.re.compile(
934 r'\s*#\s*(if|elif|else|endif|define|undef).*')
935 # Some files need specialized order of includes; exclude such files from this
936 # check.
937 uncheckable_includes_pattern = input_api.re.compile(
938 r'\s*#include '
939 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28940
941 contents = f.NewContents()
942 warnings = []
943 line_num = 0
944
[email protected]ac294a12012-12-06 16:38:43945 # Handle the special first include. If the first include file is
946 # some/path/file.h, the corresponding including file can be some/path/file.cc,
947 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
948 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33949 # If the included file is some/path/file_platform.h the including file could
950 # also be some/path/file_xxxtest_platform.h.
951 including_file_base_name = test_file_tag_pattern.sub(
952 '', input_api.os_path.basename(f.LocalPath()))
953
[email protected]ac294a12012-12-06 16:38:43954 for line in contents:
955 line_num += 1
956 if system_include_pattern.match(line):
957 # No special first include -> process the line again along with normal
958 # includes.
959 line_num -= 1
960 break
961 match = custom_include_pattern.match(line)
962 if match:
963 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33964 header_basename = test_file_tag_pattern.sub(
965 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
966
967 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24968 # No special first include -> process the line again along with normal
969 # includes.
970 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43971 break
[email protected]cf9b78f2012-11-14 11:40:28972
973 # Split into scopes: Each region between #if and #endif is its own scope.
974 scopes = []
975 current_scope = []
976 for line in contents[line_num:]:
977 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11978 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54979 continue
[email protected]2309b0fa02012-11-16 12:18:27980 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28981 scopes.append(current_scope)
982 current_scope = []
[email protected]962f117e2012-11-22 18:11:56983 elif ((system_include_pattern.match(line) or
984 custom_include_pattern.match(line)) and
985 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28986 current_scope.append((line_num, line))
987 scopes.append(current_scope)
988
989 for scope in scopes:
990 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
991 changed_linenums))
992 return warnings
993
994
995def _CheckIncludeOrder(input_api, output_api):
996 """Checks that the #include order is correct.
997
998 1. The corresponding header for source files.
999 2. C system files in alphabetical order
1000 3. C++ system files in alphabetical order
1001 4. Project's .h files in alphabetical order
1002
[email protected]ac294a12012-12-06 16:38:431003 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
1004 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:281005 """
[email protected]e120b012014-08-15 19:08:351006 def FileFilterIncludeOrder(affected_file):
1007 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
1008 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:281009
1010 warnings = []
[email protected]e120b012014-08-15 19:08:351011 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:081012 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:431013 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
1014 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:281015
1016 results = []
1017 if warnings:
[email protected]f7051d52013-04-02 18:31:421018 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:531019 warnings))
[email protected]cf9b78f2012-11-14 11:40:281020 return results
1021
1022
[email protected]70ca77752012-11-20 03:45:031023def _CheckForVersionControlConflictsInFile(input_api, f):
1024 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1025 errors = []
1026 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231027 if f.LocalPath().endswith('.md'):
1028 # First-level headers in markdown look a lot like version control
1029 # conflict markers. http://daringfireball.net/projects/markdown/basics
1030 continue
[email protected]70ca77752012-11-20 03:45:031031 if pattern.match(line):
1032 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1033 return errors
1034
1035
1036def _CheckForVersionControlConflicts(input_api, output_api):
1037 """Usually this is not intentional and will cause a compile failure."""
1038 errors = []
1039 for f in input_api.AffectedFiles():
1040 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1041
1042 results = []
1043 if errors:
1044 results.append(output_api.PresubmitError(
1045 'Version control conflict markers found, please resolve.', errors))
1046 return results
1047
estadee17314a02017-01-12 16:22:161048def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1049 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1050 errors = []
1051 for f in input_api.AffectedFiles():
1052 for line_num, line in f.ChangedContents():
1053 if pattern.search(line):
1054 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1055
1056 results = []
1057 if errors:
1058 results.append(output_api.PresubmitPromptWarning(
1059 'Found Google support URL addressed by answer number. Please replace with '
1060 'a p= identifier instead. See crbug.com/679462\n', errors))
1061 return results
1062
[email protected]70ca77752012-11-20 03:45:031063
[email protected]06e6d0ff2012-12-11 01:36:441064def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1065 def FilterFile(affected_file):
1066 """Filter function for use with input_api.AffectedSourceFiles,
1067 below. This filters out everything except non-test files from
1068 top-level directories that generally speaking should not hard-code
1069 service URLs (e.g. src/android_webview/, src/content/ and others).
1070 """
1071 return input_api.FilterSourceFile(
1072 affected_file,
[email protected]78bb39d62012-12-11 15:11:561073 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441074 black_list=(_EXCLUDED_PATHS +
1075 _TEST_CODE_EXCLUDED_PATHS +
1076 input_api.DEFAULT_BLACK_LIST))
1077
reillyi38965732015-11-16 18:27:331078 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1079 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461080 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1081 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441082 problems = [] # items are (filename, line_number, line)
1083 for f in input_api.AffectedSourceFiles(FilterFile):
1084 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461085 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441086 problems.append((f.LocalPath(), line_num, line))
1087
1088 if problems:
[email protected]f7051d52013-04-02 18:31:421089 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441090 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581091 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441092 [' %s:%d: %s' % (
1093 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031094 else:
1095 return []
[email protected]06e6d0ff2012-12-11 01:36:441096
1097
[email protected]d2530012013-01-25 16:39:271098def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1099 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311100 The native_client_sdk directory is excluded because it has auto-generated PNG
1101 files for documentation.
[email protected]d2530012013-01-25 16:39:271102 """
[email protected]d2530012013-01-25 16:39:271103 errors = []
binji0dcdf342014-12-12 18:32:311104 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1105 black_list = (r'^native_client_sdk[\\\/]',)
1106 file_filter = lambda f: input_api.FilterSourceFile(
1107 f, white_list=white_list, black_list=black_list)
1108 for f in input_api.AffectedFiles(include_deletes=False,
1109 file_filter=file_filter):
1110 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271111
1112 results = []
1113 if errors:
1114 results.append(output_api.PresubmitError(
1115 'The name of PNG files should not have abbreviations. \n'
1116 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1117 'Contact [email protected] if you have questions.', errors))
1118 return results
1119
1120
Daniel Cheng4dcdb6b2017-04-13 08:30:171121def _ExtractAddRulesFromParsedDeps(parsed_deps):
1122 """Extract the rules that add dependencies from a parsed DEPS file.
1123
1124 Args:
1125 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1126 add_rules = set()
1127 add_rules.update([
1128 rule[1:] for rule in parsed_deps.get('include_rules', [])
1129 if rule.startswith('+') or rule.startswith('!')
1130 ])
1131 for specific_file, rules in parsed_deps.get('specific_include_rules',
1132 {}).iteritems():
1133 add_rules.update([
1134 rule[1:] for rule in rules
1135 if rule.startswith('+') or rule.startswith('!')
1136 ])
1137 return add_rules
1138
1139
1140def _ParseDeps(contents):
1141 """Simple helper for parsing DEPS files."""
1142 # Stubs for handling special syntax in the root DEPS file.
1143 def FromImpl(*_):
1144 pass # NOP function so "From" doesn't fail.
1145
1146 def FileImpl(_):
1147 pass # NOP function so "File" doesn't fail.
1148
1149 class _VarImpl:
1150
1151 def __init__(self, local_scope):
1152 self._local_scope = local_scope
1153
1154 def Lookup(self, var_name):
1155 """Implements the Var syntax."""
1156 try:
1157 return self._local_scope['vars'][var_name]
1158 except KeyError:
1159 raise Exception('Var is not defined: %s' % var_name)
1160
1161 local_scope = {}
1162 global_scope = {
1163 'File': FileImpl,
1164 'From': FromImpl,
1165 'Var': _VarImpl(local_scope).Lookup,
1166 }
1167 exec contents in global_scope, local_scope
1168 return local_scope
1169
1170
1171def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081172 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411173 a set of DEPS entries that we should look up.
1174
1175 For a directory (rather than a specific filename) we fake a path to
1176 a specific filename by adding /DEPS. This is chosen as a file that
1177 will seldom or never be subject to per-file include_rules.
1178 """
[email protected]2b438d62013-11-14 17:54:141179 # We ignore deps entries on auto-generated directories.
1180 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081181
Daniel Cheng4dcdb6b2017-04-13 08:30:171182 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1183 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1184
1185 added_deps = new_deps.difference(old_deps)
1186
[email protected]2b438d62013-11-14 17:54:141187 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171188 for added_dep in added_deps:
1189 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1190 continue
1191 # Assume that a rule that ends in .h is a rule for a specific file.
1192 if added_dep.endswith('.h'):
1193 results.add(added_dep)
1194 else:
1195 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081196 return results
1197
1198
[email protected]e871964c2013-05-13 14:14:551199def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1200 """When a dependency prefixed with + is added to a DEPS file, we
1201 want to make sure that the change is reviewed by an OWNER of the
1202 target file or directory, to avoid layering violations from being
1203 introduced. This check verifies that this happens.
1204 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171205 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241206
1207 file_filter = lambda f: not input_api.re.match(
1208 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1209 for f in input_api.AffectedFiles(include_deletes=False,
1210 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551211 filename = input_api.os_path.basename(f.LocalPath())
1212 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171213 virtual_depended_on_files.update(_CalculateAddedDeps(
1214 input_api.os_path,
1215 '\n'.join(f.OldContents()),
1216 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551217
[email protected]e871964c2013-05-13 14:14:551218 if not virtual_depended_on_files:
1219 return []
1220
1221 if input_api.is_committing:
1222 if input_api.tbr:
1223 return [output_api.PresubmitNotifyResult(
1224 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271225 if input_api.dry_run:
1226 return [output_api.PresubmitNotifyResult(
1227 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551228 if not input_api.change.issue:
1229 return [output_api.PresubmitError(
1230 "DEPS approval by OWNERS check failed: this change has "
1231 "no Rietveld issue number, so we can't check it for approvals.")]
1232 output = output_api.PresubmitError
1233 else:
1234 output = output_api.PresubmitNotifyResult
1235
1236 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501237 owner_email, reviewers = (
1238 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1239 input_api,
1240 owners_db.email_regexp,
1241 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551242
1243 owner_email = owner_email or input_api.change.author_email
1244
[email protected]de4f7d22013-05-23 14:27:461245 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511246 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461247 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551248 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1249 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411250
1251 # We strip the /DEPS part that was added by
1252 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1253 # directory.
1254 def StripDeps(path):
1255 start_deps = path.rfind('/DEPS')
1256 if start_deps != -1:
1257 return path[:start_deps]
1258 else:
1259 return path
1260 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551261 for path in missing_files]
1262
1263 if unapproved_dependencies:
1264 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151265 output('You need LGTM from owners of depends-on paths in DEPS that were '
1266 'modified in this CL:\n %s' %
1267 '\n '.join(sorted(unapproved_dependencies)))]
1268 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1269 output_list.append(output(
1270 'Suggested missing target path OWNERS:\n %s' %
1271 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551272 return output_list
1273
1274 return []
1275
1276
[email protected]85218562013-11-22 07:41:401277def _CheckSpamLogging(input_api, output_api):
1278 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1279 black_list = (_EXCLUDED_PATHS +
1280 _TEST_CODE_EXCLUDED_PATHS +
1281 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501282 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191283 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481284 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461285 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121286 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1287 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581288 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161289 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031290 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151291 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1292 r"^chromecast[\\\/]",
1293 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481294 r"^components[\\\/]browser_watcher[\\\/]"
1295 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311296 r"^components[\\\/]html_viewer[\\\/]"
1297 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461298 # TODO(peter): Remove this exception. https://crbug.com/534537
1299 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1300 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251301 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1302 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241303 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111304 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151305 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111306 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521307 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501308 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361309 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311310 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131311 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001312 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441313 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451314 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021315 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351316 r"dump_file_system.cc$",
1317 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401318 source_file_filter = lambda x: input_api.FilterSourceFile(
1319 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1320
thomasanderson625d3932017-03-29 07:16:581321 log_info = set([])
1322 printf = set([])
[email protected]85218562013-11-22 07:41:401323
1324 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581325 for _, line in f.ChangedContents():
1326 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1327 log_info.add(f.LocalPath())
1328 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1329 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371330
thomasanderson625d3932017-03-29 07:16:581331 if input_api.re.search(r"\bprintf\(", line):
1332 printf.add(f.LocalPath())
1333 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1334 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401335
1336 if log_info:
1337 return [output_api.PresubmitError(
1338 'These files spam the console log with LOG(INFO):',
1339 items=log_info)]
1340 if printf:
1341 return [output_api.PresubmitError(
1342 'These files spam the console log with printf/fprintf:',
1343 items=printf)]
1344 return []
1345
1346
[email protected]49aa76a2013-12-04 06:59:161347def _CheckForAnonymousVariables(input_api, output_api):
1348 """These types are all expected to hold locks while in scope and
1349 so should never be anonymous (which causes them to be immediately
1350 destroyed)."""
1351 they_who_must_be_named = [
1352 'base::AutoLock',
1353 'base::AutoReset',
1354 'base::AutoUnlock',
1355 'SkAutoAlphaRestore',
1356 'SkAutoBitmapShaderInstall',
1357 'SkAutoBlitterChoose',
1358 'SkAutoBounderCommit',
1359 'SkAutoCallProc',
1360 'SkAutoCanvasRestore',
1361 'SkAutoCommentBlock',
1362 'SkAutoDescriptor',
1363 'SkAutoDisableDirectionCheck',
1364 'SkAutoDisableOvalCheck',
1365 'SkAutoFree',
1366 'SkAutoGlyphCache',
1367 'SkAutoHDC',
1368 'SkAutoLockColors',
1369 'SkAutoLockPixels',
1370 'SkAutoMalloc',
1371 'SkAutoMaskFreeImage',
1372 'SkAutoMutexAcquire',
1373 'SkAutoPathBoundsUpdate',
1374 'SkAutoPDFRelease',
1375 'SkAutoRasterClipValidate',
1376 'SkAutoRef',
1377 'SkAutoTime',
1378 'SkAutoTrace',
1379 'SkAutoUnref',
1380 ]
1381 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1382 # bad: base::AutoLock(lock.get());
1383 # not bad: base::AutoLock lock(lock.get());
1384 bad_pattern = input_api.re.compile(anonymous)
1385 # good: new base::AutoLock(lock.get())
1386 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1387 errors = []
1388
1389 for f in input_api.AffectedFiles():
1390 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1391 continue
1392 for linenum, line in f.ChangedContents():
1393 if bad_pattern.search(line) and not good_pattern.search(line):
1394 errors.append('%s:%d' % (f.LocalPath(), linenum))
1395
1396 if errors:
1397 return [output_api.PresubmitError(
1398 'These lines create anonymous variables that need to be named:',
1399 items=errors)]
1400 return []
1401
1402
[email protected]5fe0f8742013-11-29 01:04:591403def _CheckCygwinShell(input_api, output_api):
1404 source_file_filter = lambda x: input_api.FilterSourceFile(
1405 x, white_list=(r'.+\.(gyp|gypi)$',))
1406 cygwin_shell = []
1407
1408 for f in input_api.AffectedSourceFiles(source_file_filter):
1409 for linenum, line in f.ChangedContents():
1410 if 'msvs_cygwin_shell' in line:
1411 cygwin_shell.append(f.LocalPath())
1412 break
1413
1414 if cygwin_shell:
1415 return [output_api.PresubmitError(
1416 'These files should not use msvs_cygwin_shell (the default is 0):',
1417 items=cygwin_shell)]
1418 return []
1419
[email protected]85218562013-11-22 07:41:401420
[email protected]999261d2014-03-03 20:08:081421def _CheckUserActionUpdate(input_api, output_api):
1422 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521423 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081424 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521425 # If actions.xml is already included in the changelist, the PRESUBMIT
1426 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081427 return []
1428
[email protected]999261d2014-03-03 20:08:081429 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1430 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521431 current_actions = None
[email protected]999261d2014-03-03 20:08:081432 for f in input_api.AffectedFiles(file_filter=file_filter):
1433 for line_num, line in f.ChangedContents():
1434 match = input_api.re.search(action_re, line)
1435 if match:
[email protected]2f92dec2014-03-07 19:21:521436 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1437 # loaded only once.
1438 if not current_actions:
1439 with open('tools/metrics/actions/actions.xml') as actions_f:
1440 current_actions = actions_f.read()
1441 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081442 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521443 action = 'name="{0}"'.format(action_name)
1444 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081445 return [output_api.PresubmitPromptWarning(
1446 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521447 'tools/metrics/actions/actions.xml. Please run '
1448 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081449 % (f.LocalPath(), line_num, action_name))]
1450 return []
1451
1452
[email protected]99171a92014-06-03 08:44:471453def _GetJSONParseError(input_api, filename, eat_comments=True):
1454 try:
1455 contents = input_api.ReadFile(filename)
1456 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131457 import sys
1458 original_sys_path = sys.path
1459 try:
1460 sys.path = sys.path + [input_api.os_path.join(
1461 input_api.PresubmitLocalPath(),
1462 'tools', 'json_comment_eater')]
1463 import json_comment_eater
1464 finally:
1465 sys.path = original_sys_path
1466 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471467
1468 input_api.json.loads(contents)
1469 except ValueError as e:
1470 return e
1471 return None
1472
1473
1474def _GetIDLParseError(input_api, filename):
1475 try:
1476 contents = input_api.ReadFile(filename)
1477 idl_schema = input_api.os_path.join(
1478 input_api.PresubmitLocalPath(),
1479 'tools', 'json_schema_compiler', 'idl_schema.py')
1480 process = input_api.subprocess.Popen(
1481 [input_api.python_executable, idl_schema],
1482 stdin=input_api.subprocess.PIPE,
1483 stdout=input_api.subprocess.PIPE,
1484 stderr=input_api.subprocess.PIPE,
1485 universal_newlines=True)
1486 (_, error) = process.communicate(input=contents)
1487 return error or None
1488 except ValueError as e:
1489 return e
1490
1491
1492def _CheckParseErrors(input_api, output_api):
1493 """Check that IDL and JSON files do not contain syntax errors."""
1494 actions = {
1495 '.idl': _GetIDLParseError,
1496 '.json': _GetJSONParseError,
1497 }
1498 # These paths contain test data and other known invalid JSON files.
1499 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491500 r'test[\\\/]data[\\\/]',
1501 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471502 ]
1503 # Most JSON files are preprocessed and support comments, but these do not.
1504 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491505 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471506 ]
1507 # Only run IDL checker on files in these directories.
1508 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491509 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1510 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471511 ]
1512
1513 def get_action(affected_file):
1514 filename = affected_file.LocalPath()
1515 return actions.get(input_api.os_path.splitext(filename)[1])
1516
1517 def MatchesFile(patterns, path):
1518 for pattern in patterns:
1519 if input_api.re.search(pattern, path):
1520 return True
1521 return False
1522
1523 def FilterFile(affected_file):
1524 action = get_action(affected_file)
1525 if not action:
1526 return False
1527 path = affected_file.LocalPath()
1528
1529 if MatchesFile(excluded_patterns, path):
1530 return False
1531
1532 if (action == _GetIDLParseError and
1533 not MatchesFile(idl_included_patterns, path)):
1534 return False
1535 return True
1536
1537 results = []
1538 for affected_file in input_api.AffectedFiles(
1539 file_filter=FilterFile, include_deletes=False):
1540 action = get_action(affected_file)
1541 kwargs = {}
1542 if (action == _GetJSONParseError and
1543 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1544 kwargs['eat_comments'] = False
1545 parse_error = action(input_api,
1546 affected_file.AbsoluteLocalPath(),
1547 **kwargs)
1548 if parse_error:
1549 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1550 (affected_file.LocalPath(), parse_error)))
1551 return results
1552
1553
[email protected]760deea2013-12-10 19:33:491554def _CheckJavaStyle(input_api, output_api):
1555 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471556 import sys
[email protected]760deea2013-12-10 19:33:491557 original_sys_path = sys.path
1558 try:
1559 sys.path = sys.path + [input_api.os_path.join(
1560 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1561 import checkstyle
1562 finally:
1563 # Restore sys.path to what it was before.
1564 sys.path = original_sys_path
1565
1566 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091567 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511568 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491569
1570
dchenge07de812016-06-20 19:27:171571def _CheckIpcOwners(input_api, output_api):
1572 """Checks that affected files involving IPC have an IPC OWNERS rule.
1573
1574 Whether or not a file affects IPC is determined by a simple whitelist of
1575 filename patterns."""
1576 file_patterns = [
palmerb19a0932017-01-24 04:00:311577 # Legacy IPC:
dchenge07de812016-06-20 19:27:171578 '*_messages.cc',
1579 '*_messages*.h',
1580 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311581 # Mojo IPC:
dchenge07de812016-06-20 19:27:171582 '*.mojom',
1583 '*_struct_traits*.*',
1584 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311585 '*.typemap',
1586 # Android native IPC:
1587 '*.aidl',
1588 # Blink uses a different file naming convention:
1589 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171590 '*StructTraits*.*',
1591 '*TypeConverter*.*',
1592 ]
1593
scottmg7a6ed5ba2016-11-04 18:22:041594 # These third_party directories do not contain IPCs, but contain files
1595 # matching the above patterns, which trigger false positives.
1596 exclude_paths = [
1597 'third_party/crashpad/*',
1598 ]
1599
dchenge07de812016-06-20 19:27:171600 # Dictionary mapping an OWNERS file path to Patterns.
1601 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1602 # rules ) to a PatternEntry.
1603 # PatternEntry is a dictionary with two keys:
1604 # - 'files': the files that are matched by this pattern
1605 # - 'rules': the per-file rules needed for this pattern
1606 # For example, if we expect OWNERS file to contain rules for *.mojom and
1607 # *_struct_traits*.*, Patterns might look like this:
1608 # {
1609 # '*.mojom': {
1610 # 'files': ...,
1611 # 'rules': [
1612 # 'per-file *.mojom=set noparent',
1613 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1614 # ],
1615 # },
1616 # '*_struct_traits*.*': {
1617 # 'files': ...,
1618 # 'rules': [
1619 # 'per-file *_struct_traits*.*=set noparent',
1620 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1621 # ],
1622 # },
1623 # }
1624 to_check = {}
1625
1626 # Iterate through the affected files to see what we actually need to check
1627 # for. We should only nag patch authors about per-file rules if a file in that
1628 # directory would match that pattern. If a directory only contains *.mojom
1629 # files and no *_messages*.h files, we should only nag about rules for
1630 # *.mojom files.
rockot51249332016-06-23 16:32:251631 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171632 for pattern in file_patterns:
1633 if input_api.fnmatch.fnmatch(
1634 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041635 skip = False
1636 for exclude in exclude_paths:
1637 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1638 skip = True
1639 break
1640 if skip:
1641 continue
dchenge07de812016-06-20 19:27:171642 owners_file = input_api.os_path.join(
1643 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1644 if owners_file not in to_check:
1645 to_check[owners_file] = {}
1646 if pattern not in to_check[owners_file]:
1647 to_check[owners_file][pattern] = {
1648 'files': [],
1649 'rules': [
1650 'per-file %s=set noparent' % pattern,
1651 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1652 ]
1653 }
1654 to_check[owners_file][pattern]['files'].append(f)
1655 break
1656
1657 # Now go through the OWNERS files we collected, filtering out rules that are
1658 # already present in that OWNERS file.
1659 for owners_file, patterns in to_check.iteritems():
1660 try:
1661 with file(owners_file) as f:
1662 lines = set(f.read().splitlines())
1663 for entry in patterns.itervalues():
1664 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1665 ]
1666 except IOError:
1667 # No OWNERS file, so all the rules are definitely missing.
1668 continue
1669
1670 # All the remaining lines weren't found in OWNERS files, so emit an error.
1671 errors = []
1672 for owners_file, patterns in to_check.iteritems():
1673 missing_lines = []
1674 files = []
1675 for pattern, entry in patterns.iteritems():
1676 missing_lines.extend(entry['rules'])
1677 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1678 if missing_lines:
1679 errors.append(
1680 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1681 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1682
1683 results = []
1684 if errors:
vabrf5ce3bf92016-07-11 14:52:411685 if input_api.is_committing:
1686 output = output_api.PresubmitError
1687 else:
1688 output = output_api.PresubmitPromptWarning
1689 results.append(output(
dchenge07de812016-06-20 19:27:171690 'Found changes to IPC files without a security OWNER!',
1691 long_text='\n\n'.join(errors)))
1692
1693 return results
1694
1695
jbriance9e12f162016-11-25 07:57:501696def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311697 """Checks that added or removed lines in non third party affected
1698 header files do not lead to new useless class or struct forward
1699 declaration.
jbriance9e12f162016-11-25 07:57:501700 """
1701 results = []
1702 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1703 input_api.re.MULTILINE)
1704 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1705 input_api.re.MULTILINE)
1706 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311707 if (f.LocalPath().startswith('third_party') and
1708 not f.LocalPath().startswith('third_party/WebKit') and
1709 not f.LocalPath().startswith('third_party\\WebKit')):
1710 continue
1711
jbriance9e12f162016-11-25 07:57:501712 if not f.LocalPath().endswith('.h'):
1713 continue
1714
1715 contents = input_api.ReadFile(f)
1716 fwd_decls = input_api.re.findall(class_pattern, contents)
1717 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1718
1719 useless_fwd_decls = []
1720 for decl in fwd_decls:
1721 count = sum(1 for _ in input_api.re.finditer(
1722 r'\b%s\b' % input_api.re.escape(decl), contents))
1723 if count == 1:
1724 useless_fwd_decls.append(decl)
1725
1726 if not useless_fwd_decls:
1727 continue
1728
1729 for line in f.GenerateScmDiff().splitlines():
1730 if (line.startswith('-') and not line.startswith('--') or
1731 line.startswith('+') and not line.startswith('++')):
1732 for decl in useless_fwd_decls:
1733 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1734 results.append(output_api.PresubmitPromptWarning(
1735 '%s: %s forward declaration is becoming useless' %
1736 (f.LocalPath(), decl)))
1737 useless_fwd_decls.remove(decl)
1738
1739 return results
1740
1741
dskiba88634f4e2015-08-14 23:03:291742def _CheckAndroidToastUsage(input_api, output_api):
1743 """Checks that code uses org.chromium.ui.widget.Toast instead of
1744 android.widget.Toast (Chromium Toast doesn't force hardware
1745 acceleration on low-end devices, saving memory).
1746 """
1747 toast_import_pattern = input_api.re.compile(
1748 r'^import android\.widget\.Toast;$')
1749
1750 errors = []
1751
1752 sources = lambda affected_file: input_api.FilterSourceFile(
1753 affected_file,
1754 black_list=(_EXCLUDED_PATHS +
1755 _TEST_CODE_EXCLUDED_PATHS +
1756 input_api.DEFAULT_BLACK_LIST +
1757 (r'^chromecast[\\\/].*',
1758 r'^remoting[\\\/].*')),
1759 white_list=(r'.*\.java$',))
1760
1761 for f in input_api.AffectedSourceFiles(sources):
1762 for line_num, line in f.ChangedContents():
1763 if toast_import_pattern.search(line):
1764 errors.append("%s:%d" % (f.LocalPath(), line_num))
1765
1766 results = []
1767
1768 if errors:
1769 results.append(output_api.PresubmitError(
1770 'android.widget.Toast usage is detected. Android toasts use hardware'
1771 ' acceleration, and can be\ncostly on low-end devices. Please use'
1772 ' org.chromium.ui.widget.Toast instead.\n'
1773 'Contact [email protected] if you have any questions.',
1774 errors))
1775
1776 return results
1777
1778
dgnaa68d5e2015-06-10 10:08:221779def _CheckAndroidCrLogUsage(input_api, output_api):
1780 """Checks that new logs using org.chromium.base.Log:
1781 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511782 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221783 """
pkotwicza1dd0b002016-05-16 14:41:041784
torne89540622017-03-24 19:41:301785 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041786 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301787 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041788 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301789 # WebView license viewer code cannot depend on //base; used in stub APK.
1790 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1791 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041792 ]
1793
dgnaa68d5e2015-06-10 10:08:221794 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121795 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1796 class_in_base_pattern = input_api.re.compile(
1797 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1798 has_some_log_import_pattern = input_api.re.compile(
1799 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221800 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121801 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221802 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511803 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221804 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221805
Vincent Scheib16d7b272015-09-15 18:09:071806 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221807 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041808 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1809 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121810
dgnaa68d5e2015-06-10 10:08:221811 tag_decl_errors = []
1812 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121813 tag_errors = []
dgn38736db2015-09-18 19:20:511814 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121815 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221816
1817 for f in input_api.AffectedSourceFiles(sources):
1818 file_content = input_api.ReadFile(f)
1819 has_modified_logs = False
1820
1821 # Per line checks
dgn87d9fb62015-06-12 09:15:121822 if (cr_log_import_pattern.search(file_content) or
1823 (class_in_base_pattern.search(file_content) and
1824 not has_some_log_import_pattern.search(file_content))):
1825 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221826 for line_num, line in f.ChangedContents():
1827
1828 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121829 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221830 if match:
1831 has_modified_logs = True
1832
1833 # Make sure it uses "TAG"
1834 if not match.group('tag') == 'TAG':
1835 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121836 else:
1837 # Report non cr Log function calls in changed lines
1838 for line_num, line in f.ChangedContents():
1839 if log_call_pattern.search(line):
1840 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221841
1842 # Per file checks
1843 if has_modified_logs:
1844 # Make sure the tag is using the "cr" prefix and is not too long
1845 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511846 tag_name = match.group('name') if match else None
1847 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221848 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511849 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221850 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511851 elif '.' in tag_name:
1852 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221853
1854 results = []
1855 if tag_decl_errors:
1856 results.append(output_api.PresubmitPromptWarning(
1857 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511858 '"private static final String TAG = "<package tag>".\n'
1859 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221860 tag_decl_errors))
1861
1862 if tag_length_errors:
1863 results.append(output_api.PresubmitError(
1864 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511865 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221866 tag_length_errors))
1867
1868 if tag_errors:
1869 results.append(output_api.PresubmitPromptWarning(
1870 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1871 tag_errors))
1872
dgn87d9fb62015-06-12 09:15:121873 if util_log_errors:
dgn4401aa52015-04-29 16:26:171874 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121875 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1876 util_log_errors))
1877
dgn38736db2015-09-18 19:20:511878 if tag_with_dot_errors:
1879 results.append(output_api.PresubmitPromptWarning(
1880 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1881 tag_with_dot_errors))
1882
dgn4401aa52015-04-29 16:26:171883 return results
1884
1885
yolandyan45001472016-12-21 21:12:421886def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1887 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1888 deprecated_annotation_import_pattern = input_api.re.compile(
1889 r'^import android\.test\.suitebuilder\.annotation\..*;',
1890 input_api.re.MULTILINE)
1891 sources = lambda x: input_api.FilterSourceFile(
1892 x, white_list=(r'.*\.java$',), black_list=None)
1893 errors = []
1894 for f in input_api.AffectedFiles(sources):
1895 for line_num, line in f.ChangedContents():
1896 if deprecated_annotation_import_pattern.search(line):
1897 errors.append("%s:%d" % (f.LocalPath(), line_num))
1898
1899 results = []
1900 if errors:
1901 results.append(output_api.PresubmitError(
1902 'Annotations in android.test.suitebuilder.annotation have been'
1903 ' deprecated since API level 24. Please use android.support.test.filters'
1904 ' from //third_party/android_support_test_runner:runner_java instead.'
1905 ' Contact [email protected] if you have any questions.', errors))
1906 return results
1907
1908
agrieve7b6479d82015-10-07 14:24:221909def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1910 """Checks if MDPI assets are placed in a correct directory."""
1911 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1912 ('/res/drawable/' in f.LocalPath() or
1913 '/res/drawable-ldrtl/' in f.LocalPath()))
1914 errors = []
1915 for f in input_api.AffectedFiles(include_deletes=False,
1916 file_filter=file_filter):
1917 errors.append(' %s' % f.LocalPath())
1918
1919 results = []
1920 if errors:
1921 results.append(output_api.PresubmitError(
1922 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1923 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1924 '/res/drawable-ldrtl/.\n'
1925 'Contact [email protected] if you have questions.', errors))
1926 return results
1927
1928
agrievef32bcc72016-04-04 14:57:401929class PydepsChecker(object):
1930 def __init__(self, input_api, pydeps_files):
1931 self._file_cache = {}
1932 self._input_api = input_api
1933 self._pydeps_files = pydeps_files
1934
1935 def _LoadFile(self, path):
1936 """Returns the list of paths within a .pydeps file relative to //."""
1937 if path not in self._file_cache:
1938 with open(path) as f:
1939 self._file_cache[path] = f.read()
1940 return self._file_cache[path]
1941
1942 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1943 """Returns an interable of paths within the .pydep, relativized to //."""
1944 os_path = self._input_api.os_path
1945 pydeps_dir = os_path.dirname(pydeps_path)
1946 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1947 if not l.startswith('*'))
1948 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1949
1950 def _CreateFilesToPydepsMap(self):
1951 """Returns a map of local_path -> list_of_pydeps."""
1952 ret = {}
1953 for pydep_local_path in self._pydeps_files:
1954 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1955 ret.setdefault(path, []).append(pydep_local_path)
1956 return ret
1957
1958 def ComputeAffectedPydeps(self):
1959 """Returns an iterable of .pydeps files that might need regenerating."""
1960 affected_pydeps = set()
1961 file_to_pydeps_map = None
1962 for f in self._input_api.AffectedFiles(include_deletes=True):
1963 local_path = f.LocalPath()
1964 if local_path == 'DEPS':
1965 return self._pydeps_files
1966 elif local_path.endswith('.pydeps'):
1967 if local_path in self._pydeps_files:
1968 affected_pydeps.add(local_path)
1969 elif local_path.endswith('.py'):
1970 if file_to_pydeps_map is None:
1971 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1972 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1973 return affected_pydeps
1974
1975 def DetermineIfStale(self, pydeps_path):
1976 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411977 import difflib
agrievef32bcc72016-04-04 14:57:401978 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1979 cmd = old_pydeps_data[1][1:].strip()
1980 new_pydeps_data = self._input_api.subprocess.check_output(
1981 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411982 old_contents = old_pydeps_data[2:]
1983 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401984 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411985 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401986
1987
1988def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1989 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001990 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281991 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1992 # Mac, so skip it on other platforms.
1993 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001994 return []
agrievef32bcc72016-04-04 14:57:401995 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1996 is_android = input_api.os_path.exists('third_party/android_tools')
1997 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1998 results = []
1999 # First, check for new / deleted .pydeps.
2000 for f in input_api.AffectedFiles(include_deletes=True):
2001 if f.LocalPath().endswith('.pydeps'):
2002 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2003 results.append(output_api.PresubmitError(
2004 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2005 'remove %s' % f.LocalPath()))
2006 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2007 results.append(output_api.PresubmitError(
2008 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2009 'include %s' % f.LocalPath()))
2010
2011 if results:
2012 return results
2013
2014 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2015
2016 for pydep_path in checker.ComputeAffectedPydeps():
2017 try:
phajdan.jr0d9878552016-11-04 10:49:412018 result = checker.DetermineIfStale(pydep_path)
2019 if result:
2020 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402021 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412022 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2023 'To regenerate, run:\n\n %s' %
2024 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402025 except input_api.subprocess.CalledProcessError as error:
2026 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2027 long_text=error.output)]
2028
2029 return results
2030
2031
glidere61efad2015-02-18 17:39:432032def _CheckSingletonInHeaders(input_api, output_api):
2033 """Checks to make sure no header files have |Singleton<|."""
2034 def FileFilter(affected_file):
2035 # It's ok for base/memory/singleton.h to have |Singleton<|.
2036 black_list = (_EXCLUDED_PATHS +
2037 input_api.DEFAULT_BLACK_LIST +
2038 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
2039 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2040
sergeyu34d21222015-09-16 00:11:442041 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432042 files = []
2043 for f in input_api.AffectedSourceFiles(FileFilter):
2044 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2045 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2046 contents = input_api.ReadFile(f)
2047 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242048 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432049 pattern.search(line)):
2050 files.append(f)
2051 break
2052
2053 if files:
yolandyandaabc6d2016-04-18 18:29:392054 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442055 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432056 'Please move them to an appropriate source file so that the ' +
2057 'template gets instantiated in a single compilation unit.',
2058 files) ]
2059 return []
2060
2061
dbeam1ec68ac2016-12-15 05:22:242062def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:202063 """Checks for old style compiled_resources.gyp files."""
2064 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
2065
2066 added_compiled_resources = filter(is_compiled_resource, [
2067 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
2068 ])
2069
2070 if not added_compiled_resources:
2071 return []
2072
2073 return [output_api.PresubmitError(
2074 "Found new compiled_resources.gyp files:\n%s\n\n"
2075 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:552076 "please use compiled_resources2.gyp instead:\n"
2077 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
2078 %
dbeam37e8e7402016-02-10 22:58:202079 "\n".join(added_compiled_resources))]
2080
2081
[email protected]fd20b902014-05-09 02:14:532082_DEPRECATED_CSS = [
2083 # Values
2084 ( "-webkit-box", "flex" ),
2085 ( "-webkit-inline-box", "inline-flex" ),
2086 ( "-webkit-flex", "flex" ),
2087 ( "-webkit-inline-flex", "inline-flex" ),
2088 ( "-webkit-min-content", "min-content" ),
2089 ( "-webkit-max-content", "max-content" ),
2090
2091 # Properties
2092 ( "-webkit-background-clip", "background-clip" ),
2093 ( "-webkit-background-origin", "background-origin" ),
2094 ( "-webkit-background-size", "background-size" ),
2095 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442096 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532097
2098 # Functions
2099 ( "-webkit-gradient", "gradient" ),
2100 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2101 ( "-webkit-linear-gradient", "linear-gradient" ),
2102 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2103 ( "-webkit-radial-gradient", "radial-gradient" ),
2104 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2105]
2106
dbeam1ec68ac2016-12-15 05:22:242107def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532108 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252109 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342110 documentation and iOS CSS for dom distiller
2111 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252112 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532113 results = []
dbeam070cfe62014-10-22 06:44:022114 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252115 black_list = (_EXCLUDED_PATHS +
2116 _TEST_CODE_EXCLUDED_PATHS +
2117 input_api.DEFAULT_BLACK_LIST +
2118 (r"^chrome/common/extensions/docs",
2119 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342120 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052121 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442122 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252123 r"^native_client_sdk"))
2124 file_filter = lambda f: input_api.FilterSourceFile(
2125 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532126 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2127 for line_num, line in fpath.ChangedContents():
2128 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022129 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532130 results.append(output_api.PresubmitError(
2131 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2132 (fpath.LocalPath(), line_num, deprecated_value, value)))
2133 return results
2134
mohan.reddyf21db962014-10-16 12:26:472135
dbeam070cfe62014-10-22 06:44:022136_DEPRECATED_JS = [
2137 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2138 ( "__defineGetter__", "Object.defineProperty" ),
2139 ( "__defineSetter__", "Object.defineProperty" ),
2140]
2141
dbeam1ec68ac2016-12-15 05:22:242142def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022143 """Make sure that we don't use deprecated JS in Chrome code."""
2144 results = []
2145 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2146 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2147 input_api.DEFAULT_BLACK_LIST)
2148 file_filter = lambda f: input_api.FilterSourceFile(
2149 f, white_list=file_inclusion_pattern, black_list=black_list)
2150 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2151 for lnum, line in fpath.ChangedContents():
2152 for (deprecated, replacement) in _DEPRECATED_JS:
2153 if deprecated in line:
2154 results.append(output_api.PresubmitError(
2155 "%s:%d: Use of deprecated JS %s, use %s instead" %
2156 (fpath.LocalPath(), lnum, deprecated, replacement)))
2157 return results
2158
2159
dbeam1ec68ac2016-12-15 05:22:242160def _CheckForRiskyJsFeatures(input_api, output_api):
2161 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2162 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2163
2164 arrow_lines = []
2165 for f in input_api.AffectedFiles(file_filter=file_filter):
2166 for lnum, line in f.ChangedContents():
2167 if ' => ' in line:
2168 arrow_lines.append((f.LocalPath(), lnum))
2169
2170 if not arrow_lines:
2171 return []
2172
2173 return [output_api.PresubmitPromptWarning("""
2174Use of => operator detected in:
2175%s
2176Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2177https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2178""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2179
2180
dgnaa68d5e2015-06-10 10:08:222181def _AndroidSpecificOnUploadChecks(input_api, output_api):
2182 """Groups checks that target android code."""
2183 results = []
dgnaa68d5e2015-06-10 10:08:222184 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222185 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292186 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422187 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222188 return results
2189
2190
[email protected]22c9bd72011-03-27 16:47:392191def _CommonChecks(input_api, output_api):
2192 """Checks common to both upload and commit."""
2193 results = []
2194 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382195 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542196 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582197 results.extend(
2198 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192199 results.extend(
[email protected]760deea2013-12-10 19:33:492200 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542201 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182202 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522203 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222204 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442205 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592206 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062207 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122208 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182209 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222210 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302211 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492212 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272213 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032214 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492215 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442216 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272217 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542218 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442219 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392220 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552221 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042222 results.extend(
2223 input_api.canned_checks.CheckChangeHasNoTabs(
2224 input_api,
2225 output_api,
2226 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402227 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162228 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592229 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082230 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242231 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2232 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472233 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042234 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232235 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432236 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242237 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402238 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152239 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172240 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502241 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242242 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242243
2244 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2245 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2246 input_api, output_api,
2247 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382248 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392249 return results
[email protected]1f7b4172010-01-28 01:17:342250
[email protected]b337cb5b2011-01-23 21:24:052251
[email protected]b8079ae4a2012-12-05 19:56:492252def _CheckPatchFiles(input_api, output_api):
2253 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2254 if f.LocalPath().endswith(('.orig', '.rej'))]
2255 if problems:
2256 return [output_api.PresubmitError(
2257 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032258 else:
2259 return []
[email protected]b8079ae4a2012-12-05 19:56:492260
2261
[email protected]b00342e7f2013-03-26 16:21:542262def _DidYouMeanOSMacro(bad_macro):
2263 try:
2264 return {'A': 'OS_ANDROID',
2265 'B': 'OS_BSD',
2266 'C': 'OS_CHROMEOS',
2267 'F': 'OS_FREEBSD',
2268 'L': 'OS_LINUX',
2269 'M': 'OS_MACOSX',
2270 'N': 'OS_NACL',
2271 'O': 'OS_OPENBSD',
2272 'P': 'OS_POSIX',
2273 'S': 'OS_SOLARIS',
2274 'W': 'OS_WIN'}[bad_macro[3].upper()]
2275 except KeyError:
2276 return ''
2277
2278
2279def _CheckForInvalidOSMacrosInFile(input_api, f):
2280 """Check for sensible looking, totally invalid OS macros."""
2281 preprocessor_statement = input_api.re.compile(r'^\s*#')
2282 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2283 results = []
2284 for lnum, line in f.ChangedContents():
2285 if preprocessor_statement.search(line):
2286 for match in os_macro.finditer(line):
2287 if not match.group(1) in _VALID_OS_MACROS:
2288 good = _DidYouMeanOSMacro(match.group(1))
2289 did_you_mean = ' (did you mean %s?)' % good if good else ''
2290 results.append(' %s:%d %s%s' % (f.LocalPath(),
2291 lnum,
2292 match.group(1),
2293 did_you_mean))
2294 return results
2295
2296
2297def _CheckForInvalidOSMacros(input_api, output_api):
2298 """Check all affected files for invalid OS macros."""
2299 bad_macros = []
2300 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472301 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542302 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2303
2304 if not bad_macros:
2305 return []
2306
2307 return [output_api.PresubmitError(
2308 'Possibly invalid OS macro[s] found. Please fix your code\n'
2309 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2310
lliabraa35bab3932014-10-01 12:16:442311
2312def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2313 """Check all affected files for invalid "if defined" macros."""
2314 ALWAYS_DEFINED_MACROS = (
2315 "TARGET_CPU_PPC",
2316 "TARGET_CPU_PPC64",
2317 "TARGET_CPU_68K",
2318 "TARGET_CPU_X86",
2319 "TARGET_CPU_ARM",
2320 "TARGET_CPU_MIPS",
2321 "TARGET_CPU_SPARC",
2322 "TARGET_CPU_ALPHA",
2323 "TARGET_IPHONE_SIMULATOR",
2324 "TARGET_OS_EMBEDDED",
2325 "TARGET_OS_IPHONE",
2326 "TARGET_OS_MAC",
2327 "TARGET_OS_UNIX",
2328 "TARGET_OS_WIN32",
2329 )
2330 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2331 results = []
2332 for lnum, line in f.ChangedContents():
2333 for match in ifdef_macro.finditer(line):
2334 if match.group(1) in ALWAYS_DEFINED_MACROS:
2335 always_defined = ' %s is always defined. ' % match.group(1)
2336 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2337 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2338 lnum,
2339 always_defined,
2340 did_you_mean))
2341 return results
2342
2343
2344def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2345 """Check all affected files for invalid "if defined" macros."""
2346 bad_macros = []
2347 for f in input_api.AffectedFiles():
2348 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2349 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2350
2351 if not bad_macros:
2352 return []
2353
2354 return [output_api.PresubmitError(
2355 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2356 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2357 bad_macros)]
2358
2359
mlamouria82272622014-09-16 18:45:042360def _CheckForIPCRules(input_api, output_api):
2361 """Check for same IPC rules described in
2362 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2363 """
2364 base_pattern = r'IPC_ENUM_TRAITS\('
2365 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2366 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2367
2368 problems = []
2369 for f in input_api.AffectedSourceFiles(None):
2370 local_path = f.LocalPath()
2371 if not local_path.endswith('.h'):
2372 continue
2373 for line_number, line in f.ChangedContents():
2374 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2375 problems.append(
2376 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2377
2378 if problems:
2379 return [output_api.PresubmitPromptWarning(
2380 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2381 else:
2382 return []
2383
[email protected]b00342e7f2013-03-26 16:21:542384
mostynbb639aca52015-01-07 20:31:232385def _CheckForWindowsLineEndings(input_api, output_api):
2386 """Check source code and known ascii text files for Windows style line
2387 endings.
2388 """
earthdok1b5e0ee2015-03-10 15:19:102389 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232390
2391 file_inclusion_pattern = (
2392 known_text_files,
2393 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2394 )
2395
2396 filter = lambda f: input_api.FilterSourceFile(
2397 f, white_list=file_inclusion_pattern, black_list=None)
2398 files = [f.LocalPath() for f in
2399 input_api.AffectedSourceFiles(filter)]
2400
2401 problems = []
2402
2403 for file in files:
2404 fp = open(file, 'r')
2405 for line in fp:
2406 if line.endswith('\r\n'):
2407 problems.append(file)
2408 break
2409 fp.close()
2410
2411 if problems:
2412 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2413 'these files to contain Windows style line endings?\n' +
2414 '\n'.join(problems))]
2415
2416 return []
2417
2418
pastarmovj89f7ee12016-09-20 14:58:132419def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2420 lint_filters=None, verbose_level=None):
2421 """Checks that all source files use SYSLOG properly."""
2422 syslog_files = []
2423 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562424 for line_number, line in f.ChangedContents():
2425 if 'SYSLOG' in line:
2426 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2427
pastarmovj89f7ee12016-09-20 14:58:132428 if syslog_files:
2429 return [output_api.PresubmitPromptWarning(
2430 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2431 ' calls.\nFiles to check:\n', items=syslog_files)]
2432 return []
2433
2434
[email protected]1f7b4172010-01-28 01:17:342435def CheckChangeOnUpload(input_api, output_api):
2436 results = []
2437 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472438 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282439 results.extend(
jam93a6ee792017-02-08 23:59:222440 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192441 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222442 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132443 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162444 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542445 return results
[email protected]ca8d19842009-02-19 16:33:122446
2447
[email protected]1bfb8322014-04-23 01:02:412448def GetTryServerMasterForBot(bot):
2449 """Returns the Try Server master for the given bot.
2450
[email protected]0bb112362014-07-26 04:38:322451 It tries to guess the master from the bot name, but may still fail
2452 and return None. There is no longer a default master.
2453 """
2454 # Potentially ambiguous bot names are listed explicitly.
2455 master_map = {
tandriie5587792016-07-14 00:34:502456 'chromium_presubmit': 'master.tryserver.chromium.linux',
2457 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412458 }
[email protected]0bb112362014-07-26 04:38:322459 master = master_map.get(bot)
2460 if not master:
wnwen4fbaab82016-05-25 12:54:362461 if 'android' in bot:
tandriie5587792016-07-14 00:34:502462 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362463 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502464 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322465 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502466 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322467 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502468 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322469 return master
[email protected]1bfb8322014-04-23 01:02:412470
2471
Paweł Hajdan, Jr55083782014-12-19 20:32:562472def GetDefaultTryConfigs(bots):
2473 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012474 """
2475
Paweł Hajdan, Jr55083782014-12-19 20:32:562476 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412477
2478 # Build up the mapping from tryserver master to bot/test.
2479 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562480 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412481 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2482 return out
[email protected]38c6a512013-12-18 23:48:012483
2484
[email protected]ca8d19842009-02-19 16:33:122485def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542486 results = []
[email protected]1f7b4172010-01-28 01:17:342487 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542488 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272489 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342490 input_api,
2491 output_api,
[email protected]2fdd1f362013-01-16 03:56:032492 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272493
jam93a6ee792017-02-08 23:59:222494 results.extend(
2495 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542496 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2497 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412498 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2499 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542500 return results