blob: cacc7639313b99a102c27efe0f7758ef6338ba39 [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 ),
[email protected]127f18ec2012-06-16 05:05:59332)
333
wnwenbdc444e2016-05-25 13:44:15334
mlamouria82272622014-09-16 18:45:04335_IPC_ENUM_TRAITS_DEPRECATED = (
336 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
337 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
338
[email protected]127f18ec2012-06-16 05:05:59339
[email protected]b00342e7f2013-03-26 16:21:54340_VALID_OS_MACROS = (
341 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08342 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54343 'OS_ANDROID',
344 'OS_BSD',
345 'OS_CAT', # For testing.
346 'OS_CHROMEOS',
347 'OS_FREEBSD',
348 'OS_IOS',
349 'OS_LINUX',
350 'OS_MACOSX',
351 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21352 'OS_NACL_NONSFI',
353 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12354 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54355 'OS_OPENBSD',
356 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37357 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54358 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54359 'OS_WIN',
360)
361
362
agrievef32bcc72016-04-04 14:57:40363_ANDROID_SPECIFIC_PYDEPS_FILES = [
364 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04365 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58366 'build/secondary/third_party/android_platform/'
367 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19368 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40369]
370
wnwenbdc444e2016-05-25 13:44:15371
agrievef32bcc72016-04-04 14:57:40372_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40373]
374
wnwenbdc444e2016-05-25 13:44:15375
agrievef32bcc72016-04-04 14:57:40376_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
377
378
[email protected]55459852011-08-10 15:17:19379def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
380 """Attempts to prevent use of functions intended only for testing in
381 non-testing code. For now this is just a best-effort implementation
382 that ignores header files and may have some false positives. A
383 better implementation would probably need a proper C++ parser.
384 """
385 # We only scan .cc files and the like, as the declaration of
386 # for-testing functions in header files are hard to distinguish from
387 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44388 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19389
jochenc0d4808c2015-07-27 09:25:42390 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19391 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09392 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19393 exclusion_pattern = input_api.re.compile(
394 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
395 base_function_pattern, base_function_pattern))
396
397 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44398 black_list = (_EXCLUDED_PATHS +
399 _TEST_CODE_EXCLUDED_PATHS +
400 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19401 return input_api.FilterSourceFile(
402 affected_file,
403 white_list=(file_inclusion_pattern, ),
404 black_list=black_list)
405
406 problems = []
407 for f in input_api.AffectedSourceFiles(FilterFile):
408 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24409 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03410 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46411 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03412 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19413 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03414 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19415
416 if problems:
[email protected]f7051d52013-04-02 18:31:42417 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03418 else:
419 return []
[email protected]55459852011-08-10 15:17:19420
421
[email protected]10689ca2011-09-02 02:31:54422def _CheckNoIOStreamInHeaders(input_api, output_api):
423 """Checks to make sure no .h files include <iostream>."""
424 files = []
425 pattern = input_api.re.compile(r'^#include\s*<iostream>',
426 input_api.re.MULTILINE)
427 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
428 if not f.LocalPath().endswith('.h'):
429 continue
430 contents = input_api.ReadFile(f)
431 if pattern.search(contents):
432 files.append(f)
433
434 if len(files):
yolandyandaabc6d2016-04-18 18:29:39435 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06436 'Do not #include <iostream> in header files, since it inserts static '
437 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54438 '#include <ostream>. See http://crbug.com/94794',
439 files) ]
440 return []
441
442
[email protected]72df4e782012-06-21 16:28:18443def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52444 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18445 problems = []
446 for f in input_api.AffectedFiles():
447 if (not f.LocalPath().endswith(('.cc', '.mm'))):
448 continue
449
450 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04451 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18452 problems.append(' %s:%d' % (f.LocalPath(), line_num))
453
454 if not problems:
455 return []
456 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
457 '\n'.join(problems))]
458
459
danakj61c1aa22015-10-26 19:55:52460def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57461 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52462 errors = []
463 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
464 input_api.re.MULTILINE)
465 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
466 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
467 continue
468 for lnum, line in f.ChangedContents():
469 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17470 errors.append(output_api.PresubmitError(
471 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57472 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17473 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52474 return errors
475
476
mcasasb7440c282015-02-04 14:52:19477def _FindHistogramNameInLine(histogram_name, line):
478 """Tries to find a histogram name or prefix in a line."""
479 if not "affected-histogram" in line:
480 return histogram_name in line
481 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
482 # the histogram_name.
483 if not '"' in line:
484 return False
485 histogram_prefix = line.split('\"')[1]
486 return histogram_prefix in histogram_name
487
488
489def _CheckUmaHistogramChanges(input_api, output_api):
490 """Check that UMA histogram names in touched lines can still be found in other
491 lines of the patch or in histograms.xml. Note that this check would not catch
492 the reverse: changes in histograms.xml not matched in the code itself."""
493 touched_histograms = []
494 histograms_xml_modifications = []
495 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
496 for f in input_api.AffectedFiles():
497 # If histograms.xml itself is modified, keep the modified lines for later.
498 if f.LocalPath().endswith(('histograms.xml')):
499 histograms_xml_modifications = f.ChangedContents()
500 continue
501 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
502 continue
503 for line_num, line in f.ChangedContents():
504 found = pattern.search(line)
505 if found:
506 touched_histograms.append([found.group(1), f, line_num])
507
508 # Search for the touched histogram names in the local modifications to
509 # histograms.xml, and, if not found, on the base histograms.xml file.
510 unmatched_histograms = []
511 for histogram_info in touched_histograms:
512 histogram_name_found = False
513 for line_num, line in histograms_xml_modifications:
514 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
515 if histogram_name_found:
516 break
517 if not histogram_name_found:
518 unmatched_histograms.append(histogram_info)
519
eromanb90c82e7e32015-04-01 15:13:49520 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19521 problems = []
522 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49523 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19524 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45525 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19526 histogram_name_found = False
527 for line in histograms_xml:
528 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
529 if histogram_name_found:
530 break
531 if not histogram_name_found:
532 problems.append(' [%s:%d] %s' %
533 (f.LocalPath(), line_num, histogram_name))
534
535 if not problems:
536 return []
537 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
538 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49539 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19540
wnwenbdc444e2016-05-25 13:44:15541
yolandyandaabc6d2016-04-18 18:29:39542def _CheckFlakyTestUsage(input_api, output_api):
543 """Check that FlakyTest annotation is our own instead of the android one"""
544 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
545 files = []
546 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
547 if f.LocalPath().endswith('Test.java'):
548 if pattern.search(input_api.ReadFile(f)):
549 files.append(f)
550 if len(files):
551 return [output_api.PresubmitError(
552 'Use org.chromium.base.test.util.FlakyTest instead of '
553 'android.test.FlakyTest',
554 files)]
555 return []
mcasasb7440c282015-02-04 14:52:19556
wnwenbdc444e2016-05-25 13:44:15557
[email protected]8ea5d4b2011-09-13 21:49:22558def _CheckNoNewWStrings(input_api, output_api):
559 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27560 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22561 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20562 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57563 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34564 '/win/' in f.LocalPath() or
565 'chrome_elf' in f.LocalPath() or
566 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20567 continue
[email protected]8ea5d4b2011-09-13 21:49:22568
[email protected]a11dbe9b2012-08-07 01:32:58569 allowWString = False
[email protected]b5c24292011-11-28 14:38:20570 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58571 if 'presubmit: allow wstring' in line:
572 allowWString = True
573 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27574 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58575 allowWString = False
576 else:
577 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22578
[email protected]55463aa62011-10-12 00:48:27579 if not problems:
580 return []
581 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58582 ' If you are calling a cross-platform API that accepts a wstring, '
583 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27584 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22585
586
[email protected]2a8ac9c2011-10-19 17:20:44587def _CheckNoDEPSGIT(input_api, output_api):
588 """Make sure .DEPS.git is never modified manually."""
589 if any(f.LocalPath().endswith('.DEPS.git') for f in
590 input_api.AffectedFiles()):
591 return [output_api.PresubmitError(
592 'Never commit changes to .DEPS.git. This file is maintained by an\n'
593 'automated system based on what\'s in DEPS and your changes will be\n'
594 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34595 '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:44596 'for more information')]
597 return []
598
599
tandriief664692014-09-23 14:51:47600def _CheckValidHostsInDEPS(input_api, output_api):
601 """Checks that DEPS file deps are from allowed_hosts."""
602 # Run only if DEPS file has been modified to annoy fewer bystanders.
603 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
604 return []
605 # Outsource work to gclient verify
606 try:
607 input_api.subprocess.check_output(['gclient', 'verify'])
608 return []
609 except input_api.subprocess.CalledProcessError, error:
610 return [output_api.PresubmitError(
611 'DEPS file must have only git dependencies.',
612 long_text=error.output)]
613
614
[email protected]127f18ec2012-06-16 05:05:59615def _CheckNoBannedFunctions(input_api, output_api):
616 """Make sure that banned functions are not used."""
617 warnings = []
618 errors = []
619
wnwenbdc444e2016-05-25 13:44:15620 def IsBlacklisted(affected_file, blacklist):
621 local_path = affected_file.LocalPath()
622 for item in blacklist:
623 if input_api.re.match(item, local_path):
624 return True
625 return False
626
627 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
628 matched = False
629 if func_name[0:1] == '/':
630 regex = func_name[1:]
631 if input_api.re.search(regex, line):
632 matched = True
633 elif func_name in line:
dchenge07de812016-06-20 19:27:17634 matched = True
wnwenbdc444e2016-05-25 13:44:15635 if matched:
dchenge07de812016-06-20 19:27:17636 problems = warnings
wnwenbdc444e2016-05-25 13:44:15637 if error:
dchenge07de812016-06-20 19:27:17638 problems = errors
wnwenbdc444e2016-05-25 13:44:15639 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
640 for message_line in message:
641 problems.append(' %s' % message_line)
642
[email protected]127f18ec2012-06-16 05:05:59643 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
644 for f in input_api.AffectedFiles(file_filter=file_filter):
645 for line_num, line in f.ChangedContents():
646 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15647 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59648
649 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
650 for f in input_api.AffectedFiles(file_filter=file_filter):
651 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49652 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49653 if IsBlacklisted(f, excluded_paths):
654 continue
wnwenbdc444e2016-05-25 13:44:15655 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59656
657 result = []
658 if (warnings):
659 result.append(output_api.PresubmitPromptWarning(
660 'Banned functions were used.\n' + '\n'.join(warnings)))
661 if (errors):
662 result.append(output_api.PresubmitError(
663 'Banned functions were used.\n' + '\n'.join(errors)))
664 return result
665
666
[email protected]6c063c62012-07-11 19:11:06667def _CheckNoPragmaOnce(input_api, output_api):
668 """Make sure that banned functions are not used."""
669 files = []
670 pattern = input_api.re.compile(r'^#pragma\s+once',
671 input_api.re.MULTILINE)
672 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
673 if not f.LocalPath().endswith('.h'):
674 continue
675 contents = input_api.ReadFile(f)
676 if pattern.search(contents):
677 files.append(f)
678
679 if files:
680 return [output_api.PresubmitError(
681 'Do not use #pragma once in header files.\n'
682 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
683 files)]
684 return []
685
[email protected]127f18ec2012-06-16 05:05:59686
[email protected]e7479052012-09-19 00:26:12687def _CheckNoTrinaryTrueFalse(input_api, output_api):
688 """Checks to make sure we don't introduce use of foo ? true : false."""
689 problems = []
690 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
691 for f in input_api.AffectedFiles():
692 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
693 continue
694
695 for line_num, line in f.ChangedContents():
696 if pattern.match(line):
697 problems.append(' %s:%d' % (f.LocalPath(), line_num))
698
699 if not problems:
700 return []
701 return [output_api.PresubmitPromptWarning(
702 'Please consider avoiding the "? true : false" pattern if possible.\n' +
703 '\n'.join(problems))]
704
705
[email protected]55f9f382012-07-31 11:02:18706def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28707 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18708 change. Breaking - rules is an error, breaking ! rules is a
709 warning.
710 """
mohan.reddyf21db962014-10-16 12:26:47711 import sys
[email protected]55f9f382012-07-31 11:02:18712 # We need to wait until we have an input_api object and use this
713 # roundabout construct to import checkdeps because this file is
714 # eval-ed and thus doesn't have __file__.
715 original_sys_path = sys.path
716 try:
717 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47718 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18719 import checkdeps
720 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28721 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18722 from rules import Rule
723 finally:
724 # Restore sys.path to what it was before.
725 sys.path = original_sys_path
726
727 added_includes = []
rhalavati08acd232017-04-03 07:23:28728 added_imports = []
[email protected]55f9f382012-07-31 11:02:18729 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28730 if CppChecker.IsCppFile(f.LocalPath()):
731 changed_lines = [line for line_num, line in f.ChangedContents()]
732 added_includes.append([f.LocalPath(), changed_lines])
733 elif ProtoChecker.IsProtoFile(f.LocalPath()):
734 changed_lines = [line for line_num, line in f.ChangedContents()]
735 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18736
[email protected]26385172013-05-09 23:11:35737 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18738
739 error_descriptions = []
740 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28741 error_subjects = set()
742 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18743 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
744 added_includes):
745 description_with_path = '%s\n %s' % (path, rule_description)
746 if rule_type == Rule.DISALLOW:
747 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28748 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18749 else:
750 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28751 warning_subjects.add("#includes")
752
753 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
754 added_imports):
755 description_with_path = '%s\n %s' % (path, rule_description)
756 if rule_type == Rule.DISALLOW:
757 error_descriptions.append(description_with_path)
758 error_subjects.add("imports")
759 else:
760 warning_descriptions.append(description_with_path)
761 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18762
763 results = []
764 if error_descriptions:
765 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28766 'You added one or more %s that violate checkdeps rules.'
767 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18768 error_descriptions))
769 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42770 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28771 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18772 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28773 '%s? See relevant DEPS file(s) for details and contacts.' %
774 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18775 warning_descriptions))
776 return results
777
778
[email protected]fbcafe5a2012-08-08 15:31:22779def _CheckFilePermissions(input_api, output_api):
780 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15781 if input_api.platform == 'win32':
782 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29783 checkperms_tool = input_api.os_path.join(
784 input_api.PresubmitLocalPath(),
785 'tools', 'checkperms', 'checkperms.py')
786 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47787 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22788 for f in input_api.AffectedFiles():
789 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11790 try:
791 input_api.subprocess.check_output(args)
792 return []
793 except input_api.subprocess.CalledProcessError as error:
794 return [output_api.PresubmitError(
795 'checkperms.py failed:',
796 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22797
798
robertocn832f5992017-01-04 19:01:30799def _CheckTeamTags(input_api, output_api):
800 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
801 checkteamtags_tool = input_api.os_path.join(
802 input_api.PresubmitLocalPath(),
803 'tools', 'checkteamtags', 'checkteamtags.py')
804 args = [input_api.python_executable, checkteamtags_tool,
805 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22806 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30807 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
808 'OWNERS']
809 try:
810 if files:
811 input_api.subprocess.check_output(args + files)
812 return []
813 except input_api.subprocess.CalledProcessError as error:
814 return [output_api.PresubmitError(
815 'checkteamtags.py failed:',
816 long_text=error.output)]
817
818
[email protected]c8278b32012-10-30 20:35:49819def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
820 """Makes sure we don't include ui/aura/window_property.h
821 in header files.
822 """
823 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
824 errors = []
825 for f in input_api.AffectedFiles():
826 if not f.LocalPath().endswith('.h'):
827 continue
828 for line_num, line in f.ChangedContents():
829 if pattern.match(line):
830 errors.append(' %s:%d' % (f.LocalPath(), line_num))
831
832 results = []
833 if errors:
834 results.append(output_api.PresubmitError(
835 'Header files should not include ui/aura/window_property.h', errors))
836 return results
837
838
[email protected]cf9b78f2012-11-14 11:40:28839def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
840 """Checks that the lines in scope occur in the right order.
841
842 1. C system files in alphabetical order
843 2. C++ system files in alphabetical order
844 3. Project's .h files
845 """
846
847 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
848 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
849 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
850
851 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
852
853 state = C_SYSTEM_INCLUDES
854
855 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57856 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28857 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55858 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28859 for line_num, line in scope:
860 if c_system_include_pattern.match(line):
861 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55862 problem_linenums.append((line_num, previous_line_num,
863 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28864 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55865 problem_linenums.append((line_num, previous_line_num,
866 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28867 elif cpp_system_include_pattern.match(line):
868 if state == C_SYSTEM_INCLUDES:
869 state = CPP_SYSTEM_INCLUDES
870 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55871 problem_linenums.append((line_num, previous_line_num,
872 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28873 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55874 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28875 elif custom_include_pattern.match(line):
876 if state != CUSTOM_INCLUDES:
877 state = CUSTOM_INCLUDES
878 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55879 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28880 else:
brucedawson70fadb02015-06-30 17:47:55881 problem_linenums.append((line_num, previous_line_num,
882 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28883 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57884 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28885
886 warnings = []
brucedawson70fadb02015-06-30 17:47:55887 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57888 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55889 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28890 return warnings
891
892
[email protected]ac294a12012-12-06 16:38:43893def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28894 """Checks the #include order for the given file f."""
895
[email protected]2299dcf2012-11-15 19:56:24896 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30897 # Exclude the following includes from the check:
898 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
899 # specific order.
900 # 2) <atlbase.h>, "build/build_config.h"
901 excluded_include_pattern = input_api.re.compile(
902 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24903 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33904 # Match the final or penultimate token if it is xxxtest so we can ignore it
905 # when considering the special first include.
906 test_file_tag_pattern = input_api.re.compile(
907 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11908 if_pattern = input_api.re.compile(
909 r'\s*#\s*(if|elif|else|endif|define|undef).*')
910 # Some files need specialized order of includes; exclude such files from this
911 # check.
912 uncheckable_includes_pattern = input_api.re.compile(
913 r'\s*#include '
914 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28915
916 contents = f.NewContents()
917 warnings = []
918 line_num = 0
919
[email protected]ac294a12012-12-06 16:38:43920 # Handle the special first include. If the first include file is
921 # some/path/file.h, the corresponding including file can be some/path/file.cc,
922 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
923 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33924 # If the included file is some/path/file_platform.h the including file could
925 # also be some/path/file_xxxtest_platform.h.
926 including_file_base_name = test_file_tag_pattern.sub(
927 '', input_api.os_path.basename(f.LocalPath()))
928
[email protected]ac294a12012-12-06 16:38:43929 for line in contents:
930 line_num += 1
931 if system_include_pattern.match(line):
932 # No special first include -> process the line again along with normal
933 # includes.
934 line_num -= 1
935 break
936 match = custom_include_pattern.match(line)
937 if match:
938 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33939 header_basename = test_file_tag_pattern.sub(
940 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
941
942 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24943 # No special first include -> process the line again along with normal
944 # includes.
945 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43946 break
[email protected]cf9b78f2012-11-14 11:40:28947
948 # Split into scopes: Each region between #if and #endif is its own scope.
949 scopes = []
950 current_scope = []
951 for line in contents[line_num:]:
952 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11953 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54954 continue
[email protected]2309b0fa02012-11-16 12:18:27955 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28956 scopes.append(current_scope)
957 current_scope = []
[email protected]962f117e2012-11-22 18:11:56958 elif ((system_include_pattern.match(line) or
959 custom_include_pattern.match(line)) and
960 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28961 current_scope.append((line_num, line))
962 scopes.append(current_scope)
963
964 for scope in scopes:
965 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
966 changed_linenums))
967 return warnings
968
969
970def _CheckIncludeOrder(input_api, output_api):
971 """Checks that the #include order is correct.
972
973 1. The corresponding header for source files.
974 2. C system files in alphabetical order
975 3. C++ system files in alphabetical order
976 4. Project's .h files in alphabetical order
977
[email protected]ac294a12012-12-06 16:38:43978 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
979 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28980 """
[email protected]e120b012014-08-15 19:08:35981 def FileFilterIncludeOrder(affected_file):
982 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
983 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28984
985 warnings = []
[email protected]e120b012014-08-15 19:08:35986 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08987 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43988 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
989 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28990
991 results = []
992 if warnings:
[email protected]f7051d52013-04-02 18:31:42993 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53994 warnings))
[email protected]cf9b78f2012-11-14 11:40:28995 return results
996
997
[email protected]70ca77752012-11-20 03:45:03998def _CheckForVersionControlConflictsInFile(input_api, f):
999 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1000 errors = []
1001 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231002 if f.LocalPath().endswith('.md'):
1003 # First-level headers in markdown look a lot like version control
1004 # conflict markers. http://daringfireball.net/projects/markdown/basics
1005 continue
[email protected]70ca77752012-11-20 03:45:031006 if pattern.match(line):
1007 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1008 return errors
1009
1010
1011def _CheckForVersionControlConflicts(input_api, output_api):
1012 """Usually this is not intentional and will cause a compile failure."""
1013 errors = []
1014 for f in input_api.AffectedFiles():
1015 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1016
1017 results = []
1018 if errors:
1019 results.append(output_api.PresubmitError(
1020 'Version control conflict markers found, please resolve.', errors))
1021 return results
1022
estadee17314a02017-01-12 16:22:161023def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1024 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1025 errors = []
1026 for f in input_api.AffectedFiles():
1027 for line_num, line in f.ChangedContents():
1028 if pattern.search(line):
1029 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1030
1031 results = []
1032 if errors:
1033 results.append(output_api.PresubmitPromptWarning(
1034 'Found Google support URL addressed by answer number. Please replace with '
1035 'a p= identifier instead. See crbug.com/679462\n', errors))
1036 return results
1037
[email protected]70ca77752012-11-20 03:45:031038
[email protected]06e6d0ff2012-12-11 01:36:441039def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1040 def FilterFile(affected_file):
1041 """Filter function for use with input_api.AffectedSourceFiles,
1042 below. This filters out everything except non-test files from
1043 top-level directories that generally speaking should not hard-code
1044 service URLs (e.g. src/android_webview/, src/content/ and others).
1045 """
1046 return input_api.FilterSourceFile(
1047 affected_file,
[email protected]78bb39d62012-12-11 15:11:561048 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441049 black_list=(_EXCLUDED_PATHS +
1050 _TEST_CODE_EXCLUDED_PATHS +
1051 input_api.DEFAULT_BLACK_LIST))
1052
reillyi38965732015-11-16 18:27:331053 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1054 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461055 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1056 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441057 problems = [] # items are (filename, line_number, line)
1058 for f in input_api.AffectedSourceFiles(FilterFile):
1059 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461060 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441061 problems.append((f.LocalPath(), line_num, line))
1062
1063 if problems:
[email protected]f7051d52013-04-02 18:31:421064 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441065 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581066 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441067 [' %s:%d: %s' % (
1068 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031069 else:
1070 return []
[email protected]06e6d0ff2012-12-11 01:36:441071
1072
[email protected]d2530012013-01-25 16:39:271073def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1074 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311075 The native_client_sdk directory is excluded because it has auto-generated PNG
1076 files for documentation.
[email protected]d2530012013-01-25 16:39:271077 """
[email protected]d2530012013-01-25 16:39:271078 errors = []
binji0dcdf342014-12-12 18:32:311079 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1080 black_list = (r'^native_client_sdk[\\\/]',)
1081 file_filter = lambda f: input_api.FilterSourceFile(
1082 f, white_list=white_list, black_list=black_list)
1083 for f in input_api.AffectedFiles(include_deletes=False,
1084 file_filter=file_filter):
1085 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271086
1087 results = []
1088 if errors:
1089 results.append(output_api.PresubmitError(
1090 'The name of PNG files should not have abbreviations. \n'
1091 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1092 'Contact [email protected] if you have questions.', errors))
1093 return results
1094
1095
Daniel Cheng4dcdb6b2017-04-13 08:30:171096def _ExtractAddRulesFromParsedDeps(parsed_deps):
1097 """Extract the rules that add dependencies from a parsed DEPS file.
1098
1099 Args:
1100 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1101 add_rules = set()
1102 add_rules.update([
1103 rule[1:] for rule in parsed_deps.get('include_rules', [])
1104 if rule.startswith('+') or rule.startswith('!')
1105 ])
1106 for specific_file, rules in parsed_deps.get('specific_include_rules',
1107 {}).iteritems():
1108 add_rules.update([
1109 rule[1:] for rule in rules
1110 if rule.startswith('+') or rule.startswith('!')
1111 ])
1112 return add_rules
1113
1114
1115def _ParseDeps(contents):
1116 """Simple helper for parsing DEPS files."""
1117 # Stubs for handling special syntax in the root DEPS file.
1118 def FromImpl(*_):
1119 pass # NOP function so "From" doesn't fail.
1120
1121 def FileImpl(_):
1122 pass # NOP function so "File" doesn't fail.
1123
1124 class _VarImpl:
1125
1126 def __init__(self, local_scope):
1127 self._local_scope = local_scope
1128
1129 def Lookup(self, var_name):
1130 """Implements the Var syntax."""
1131 try:
1132 return self._local_scope['vars'][var_name]
1133 except KeyError:
1134 raise Exception('Var is not defined: %s' % var_name)
1135
1136 local_scope = {}
1137 global_scope = {
1138 'File': FileImpl,
1139 'From': FromImpl,
1140 'Var': _VarImpl(local_scope).Lookup,
1141 }
1142 exec contents in global_scope, local_scope
1143 return local_scope
1144
1145
1146def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081147 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411148 a set of DEPS entries that we should look up.
1149
1150 For a directory (rather than a specific filename) we fake a path to
1151 a specific filename by adding /DEPS. This is chosen as a file that
1152 will seldom or never be subject to per-file include_rules.
1153 """
[email protected]2b438d62013-11-14 17:54:141154 # We ignore deps entries on auto-generated directories.
1155 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081156
Daniel Cheng4dcdb6b2017-04-13 08:30:171157 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1158 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1159
1160 added_deps = new_deps.difference(old_deps)
1161
[email protected]2b438d62013-11-14 17:54:141162 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171163 for added_dep in added_deps:
1164 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1165 continue
1166 # Assume that a rule that ends in .h is a rule for a specific file.
1167 if added_dep.endswith('.h'):
1168 results.add(added_dep)
1169 else:
1170 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081171 return results
1172
1173
[email protected]e871964c2013-05-13 14:14:551174def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1175 """When a dependency prefixed with + is added to a DEPS file, we
1176 want to make sure that the change is reviewed by an OWNER of the
1177 target file or directory, to avoid layering violations from being
1178 introduced. This check verifies that this happens.
1179 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171180 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241181
1182 file_filter = lambda f: not input_api.re.match(
1183 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1184 for f in input_api.AffectedFiles(include_deletes=False,
1185 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551186 filename = input_api.os_path.basename(f.LocalPath())
1187 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171188 virtual_depended_on_files.update(_CalculateAddedDeps(
1189 input_api.os_path,
1190 '\n'.join(f.OldContents()),
1191 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551192
[email protected]e871964c2013-05-13 14:14:551193 if not virtual_depended_on_files:
1194 return []
1195
1196 if input_api.is_committing:
1197 if input_api.tbr:
1198 return [output_api.PresubmitNotifyResult(
1199 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271200 if input_api.dry_run:
1201 return [output_api.PresubmitNotifyResult(
1202 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551203 if not input_api.change.issue:
1204 return [output_api.PresubmitError(
1205 "DEPS approval by OWNERS check failed: this change has "
1206 "no Rietveld issue number, so we can't check it for approvals.")]
1207 output = output_api.PresubmitError
1208 else:
1209 output = output_api.PresubmitNotifyResult
1210
1211 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501212 owner_email, reviewers = (
1213 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1214 input_api,
1215 owners_db.email_regexp,
1216 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551217
1218 owner_email = owner_email or input_api.change.author_email
1219
[email protected]de4f7d22013-05-23 14:27:461220 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511221 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461222 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551223 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1224 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411225
1226 # We strip the /DEPS part that was added by
1227 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1228 # directory.
1229 def StripDeps(path):
1230 start_deps = path.rfind('/DEPS')
1231 if start_deps != -1:
1232 return path[:start_deps]
1233 else:
1234 return path
1235 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551236 for path in missing_files]
1237
1238 if unapproved_dependencies:
1239 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151240 output('You need LGTM from owners of depends-on paths in DEPS that were '
1241 'modified in this CL:\n %s' %
1242 '\n '.join(sorted(unapproved_dependencies)))]
1243 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1244 output_list.append(output(
1245 'Suggested missing target path OWNERS:\n %s' %
1246 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551247 return output_list
1248
1249 return []
1250
1251
[email protected]85218562013-11-22 07:41:401252def _CheckSpamLogging(input_api, output_api):
1253 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1254 black_list = (_EXCLUDED_PATHS +
1255 _TEST_CODE_EXCLUDED_PATHS +
1256 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501257 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191258 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481259 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461260 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121261 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1262 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581263 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161264 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031265 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151266 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1267 r"^chromecast[\\\/]",
1268 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481269 r"^components[\\\/]browser_watcher[\\\/]"
1270 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311271 r"^components[\\\/]html_viewer[\\\/]"
1272 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461273 # TODO(peter): Remove this exception. https://crbug.com/534537
1274 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1275 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251276 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1277 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241278 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111279 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151280 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111281 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521282 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501283 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361284 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311285 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131286 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001287 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441288 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451289 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021290 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351291 r"dump_file_system.cc$",
1292 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401293 source_file_filter = lambda x: input_api.FilterSourceFile(
1294 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1295
thomasanderson625d3932017-03-29 07:16:581296 log_info = set([])
1297 printf = set([])
[email protected]85218562013-11-22 07:41:401298
1299 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581300 for _, line in f.ChangedContents():
1301 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1302 log_info.add(f.LocalPath())
1303 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1304 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371305
thomasanderson625d3932017-03-29 07:16:581306 if input_api.re.search(r"\bprintf\(", line):
1307 printf.add(f.LocalPath())
1308 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1309 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401310
1311 if log_info:
1312 return [output_api.PresubmitError(
1313 'These files spam the console log with LOG(INFO):',
1314 items=log_info)]
1315 if printf:
1316 return [output_api.PresubmitError(
1317 'These files spam the console log with printf/fprintf:',
1318 items=printf)]
1319 return []
1320
1321
[email protected]49aa76a2013-12-04 06:59:161322def _CheckForAnonymousVariables(input_api, output_api):
1323 """These types are all expected to hold locks while in scope and
1324 so should never be anonymous (which causes them to be immediately
1325 destroyed)."""
1326 they_who_must_be_named = [
1327 'base::AutoLock',
1328 'base::AutoReset',
1329 'base::AutoUnlock',
1330 'SkAutoAlphaRestore',
1331 'SkAutoBitmapShaderInstall',
1332 'SkAutoBlitterChoose',
1333 'SkAutoBounderCommit',
1334 'SkAutoCallProc',
1335 'SkAutoCanvasRestore',
1336 'SkAutoCommentBlock',
1337 'SkAutoDescriptor',
1338 'SkAutoDisableDirectionCheck',
1339 'SkAutoDisableOvalCheck',
1340 'SkAutoFree',
1341 'SkAutoGlyphCache',
1342 'SkAutoHDC',
1343 'SkAutoLockColors',
1344 'SkAutoLockPixels',
1345 'SkAutoMalloc',
1346 'SkAutoMaskFreeImage',
1347 'SkAutoMutexAcquire',
1348 'SkAutoPathBoundsUpdate',
1349 'SkAutoPDFRelease',
1350 'SkAutoRasterClipValidate',
1351 'SkAutoRef',
1352 'SkAutoTime',
1353 'SkAutoTrace',
1354 'SkAutoUnref',
1355 ]
1356 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1357 # bad: base::AutoLock(lock.get());
1358 # not bad: base::AutoLock lock(lock.get());
1359 bad_pattern = input_api.re.compile(anonymous)
1360 # good: new base::AutoLock(lock.get())
1361 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1362 errors = []
1363
1364 for f in input_api.AffectedFiles():
1365 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1366 continue
1367 for linenum, line in f.ChangedContents():
1368 if bad_pattern.search(line) and not good_pattern.search(line):
1369 errors.append('%s:%d' % (f.LocalPath(), linenum))
1370
1371 if errors:
1372 return [output_api.PresubmitError(
1373 'These lines create anonymous variables that need to be named:',
1374 items=errors)]
1375 return []
1376
1377
[email protected]5fe0f8742013-11-29 01:04:591378def _CheckCygwinShell(input_api, output_api):
1379 source_file_filter = lambda x: input_api.FilterSourceFile(
1380 x, white_list=(r'.+\.(gyp|gypi)$',))
1381 cygwin_shell = []
1382
1383 for f in input_api.AffectedSourceFiles(source_file_filter):
1384 for linenum, line in f.ChangedContents():
1385 if 'msvs_cygwin_shell' in line:
1386 cygwin_shell.append(f.LocalPath())
1387 break
1388
1389 if cygwin_shell:
1390 return [output_api.PresubmitError(
1391 'These files should not use msvs_cygwin_shell (the default is 0):',
1392 items=cygwin_shell)]
1393 return []
1394
[email protected]85218562013-11-22 07:41:401395
[email protected]999261d2014-03-03 20:08:081396def _CheckUserActionUpdate(input_api, output_api):
1397 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521398 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081399 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521400 # If actions.xml is already included in the changelist, the PRESUBMIT
1401 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081402 return []
1403
[email protected]999261d2014-03-03 20:08:081404 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1405 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521406 current_actions = None
[email protected]999261d2014-03-03 20:08:081407 for f in input_api.AffectedFiles(file_filter=file_filter):
1408 for line_num, line in f.ChangedContents():
1409 match = input_api.re.search(action_re, line)
1410 if match:
[email protected]2f92dec2014-03-07 19:21:521411 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1412 # loaded only once.
1413 if not current_actions:
1414 with open('tools/metrics/actions/actions.xml') as actions_f:
1415 current_actions = actions_f.read()
1416 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081417 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521418 action = 'name="{0}"'.format(action_name)
1419 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081420 return [output_api.PresubmitPromptWarning(
1421 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521422 'tools/metrics/actions/actions.xml. Please run '
1423 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081424 % (f.LocalPath(), line_num, action_name))]
1425 return []
1426
1427
[email protected]99171a92014-06-03 08:44:471428def _GetJSONParseError(input_api, filename, eat_comments=True):
1429 try:
1430 contents = input_api.ReadFile(filename)
1431 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131432 import sys
1433 original_sys_path = sys.path
1434 try:
1435 sys.path = sys.path + [input_api.os_path.join(
1436 input_api.PresubmitLocalPath(),
1437 'tools', 'json_comment_eater')]
1438 import json_comment_eater
1439 finally:
1440 sys.path = original_sys_path
1441 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471442
1443 input_api.json.loads(contents)
1444 except ValueError as e:
1445 return e
1446 return None
1447
1448
1449def _GetIDLParseError(input_api, filename):
1450 try:
1451 contents = input_api.ReadFile(filename)
1452 idl_schema = input_api.os_path.join(
1453 input_api.PresubmitLocalPath(),
1454 'tools', 'json_schema_compiler', 'idl_schema.py')
1455 process = input_api.subprocess.Popen(
1456 [input_api.python_executable, idl_schema],
1457 stdin=input_api.subprocess.PIPE,
1458 stdout=input_api.subprocess.PIPE,
1459 stderr=input_api.subprocess.PIPE,
1460 universal_newlines=True)
1461 (_, error) = process.communicate(input=contents)
1462 return error or None
1463 except ValueError as e:
1464 return e
1465
1466
1467def _CheckParseErrors(input_api, output_api):
1468 """Check that IDL and JSON files do not contain syntax errors."""
1469 actions = {
1470 '.idl': _GetIDLParseError,
1471 '.json': _GetJSONParseError,
1472 }
1473 # These paths contain test data and other known invalid JSON files.
1474 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491475 r'test[\\\/]data[\\\/]',
1476 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471477 ]
1478 # Most JSON files are preprocessed and support comments, but these do not.
1479 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491480 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471481 ]
1482 # Only run IDL checker on files in these directories.
1483 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491484 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1485 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471486 ]
1487
1488 def get_action(affected_file):
1489 filename = affected_file.LocalPath()
1490 return actions.get(input_api.os_path.splitext(filename)[1])
1491
1492 def MatchesFile(patterns, path):
1493 for pattern in patterns:
1494 if input_api.re.search(pattern, path):
1495 return True
1496 return False
1497
1498 def FilterFile(affected_file):
1499 action = get_action(affected_file)
1500 if not action:
1501 return False
1502 path = affected_file.LocalPath()
1503
1504 if MatchesFile(excluded_patterns, path):
1505 return False
1506
1507 if (action == _GetIDLParseError and
1508 not MatchesFile(idl_included_patterns, path)):
1509 return False
1510 return True
1511
1512 results = []
1513 for affected_file in input_api.AffectedFiles(
1514 file_filter=FilterFile, include_deletes=False):
1515 action = get_action(affected_file)
1516 kwargs = {}
1517 if (action == _GetJSONParseError and
1518 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1519 kwargs['eat_comments'] = False
1520 parse_error = action(input_api,
1521 affected_file.AbsoluteLocalPath(),
1522 **kwargs)
1523 if parse_error:
1524 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1525 (affected_file.LocalPath(), parse_error)))
1526 return results
1527
1528
[email protected]760deea2013-12-10 19:33:491529def _CheckJavaStyle(input_api, output_api):
1530 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471531 import sys
[email protected]760deea2013-12-10 19:33:491532 original_sys_path = sys.path
1533 try:
1534 sys.path = sys.path + [input_api.os_path.join(
1535 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1536 import checkstyle
1537 finally:
1538 # Restore sys.path to what it was before.
1539 sys.path = original_sys_path
1540
1541 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091542 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511543 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491544
1545
dchenge07de812016-06-20 19:27:171546def _CheckIpcOwners(input_api, output_api):
1547 """Checks that affected files involving IPC have an IPC OWNERS rule.
1548
1549 Whether or not a file affects IPC is determined by a simple whitelist of
1550 filename patterns."""
1551 file_patterns = [
palmerb19a0932017-01-24 04:00:311552 # Legacy IPC:
dchenge07de812016-06-20 19:27:171553 '*_messages.cc',
1554 '*_messages*.h',
1555 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311556 # Mojo IPC:
dchenge07de812016-06-20 19:27:171557 '*.mojom',
1558 '*_struct_traits*.*',
1559 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311560 '*.typemap',
1561 # Android native IPC:
1562 '*.aidl',
1563 # Blink uses a different file naming convention:
1564 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171565 '*StructTraits*.*',
1566 '*TypeConverter*.*',
1567 ]
1568
scottmg7a6ed5ba2016-11-04 18:22:041569 # These third_party directories do not contain IPCs, but contain files
1570 # matching the above patterns, which trigger false positives.
1571 exclude_paths = [
1572 'third_party/crashpad/*',
1573 ]
1574
dchenge07de812016-06-20 19:27:171575 # Dictionary mapping an OWNERS file path to Patterns.
1576 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1577 # rules ) to a PatternEntry.
1578 # PatternEntry is a dictionary with two keys:
1579 # - 'files': the files that are matched by this pattern
1580 # - 'rules': the per-file rules needed for this pattern
1581 # For example, if we expect OWNERS file to contain rules for *.mojom and
1582 # *_struct_traits*.*, Patterns might look like this:
1583 # {
1584 # '*.mojom': {
1585 # 'files': ...,
1586 # 'rules': [
1587 # 'per-file *.mojom=set noparent',
1588 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1589 # ],
1590 # },
1591 # '*_struct_traits*.*': {
1592 # 'files': ...,
1593 # 'rules': [
1594 # 'per-file *_struct_traits*.*=set noparent',
1595 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1596 # ],
1597 # },
1598 # }
1599 to_check = {}
1600
1601 # Iterate through the affected files to see what we actually need to check
1602 # for. We should only nag patch authors about per-file rules if a file in that
1603 # directory would match that pattern. If a directory only contains *.mojom
1604 # files and no *_messages*.h files, we should only nag about rules for
1605 # *.mojom files.
rockot51249332016-06-23 16:32:251606 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171607 for pattern in file_patterns:
1608 if input_api.fnmatch.fnmatch(
1609 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041610 skip = False
1611 for exclude in exclude_paths:
1612 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1613 skip = True
1614 break
1615 if skip:
1616 continue
dchenge07de812016-06-20 19:27:171617 owners_file = input_api.os_path.join(
1618 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1619 if owners_file not in to_check:
1620 to_check[owners_file] = {}
1621 if pattern not in to_check[owners_file]:
1622 to_check[owners_file][pattern] = {
1623 'files': [],
1624 'rules': [
1625 'per-file %s=set noparent' % pattern,
1626 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1627 ]
1628 }
1629 to_check[owners_file][pattern]['files'].append(f)
1630 break
1631
1632 # Now go through the OWNERS files we collected, filtering out rules that are
1633 # already present in that OWNERS file.
1634 for owners_file, patterns in to_check.iteritems():
1635 try:
1636 with file(owners_file) as f:
1637 lines = set(f.read().splitlines())
1638 for entry in patterns.itervalues():
1639 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1640 ]
1641 except IOError:
1642 # No OWNERS file, so all the rules are definitely missing.
1643 continue
1644
1645 # All the remaining lines weren't found in OWNERS files, so emit an error.
1646 errors = []
1647 for owners_file, patterns in to_check.iteritems():
1648 missing_lines = []
1649 files = []
1650 for pattern, entry in patterns.iteritems():
1651 missing_lines.extend(entry['rules'])
1652 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1653 if missing_lines:
1654 errors.append(
1655 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1656 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1657
1658 results = []
1659 if errors:
vabrf5ce3bf92016-07-11 14:52:411660 if input_api.is_committing:
1661 output = output_api.PresubmitError
1662 else:
1663 output = output_api.PresubmitPromptWarning
1664 results.append(output(
dchenge07de812016-06-20 19:27:171665 'Found changes to IPC files without a security OWNER!',
1666 long_text='\n\n'.join(errors)))
1667
1668 return results
1669
1670
jbriance9e12f162016-11-25 07:57:501671def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311672 """Checks that added or removed lines in non third party affected
1673 header files do not lead to new useless class or struct forward
1674 declaration.
jbriance9e12f162016-11-25 07:57:501675 """
1676 results = []
1677 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1678 input_api.re.MULTILINE)
1679 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1680 input_api.re.MULTILINE)
1681 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311682 if (f.LocalPath().startswith('third_party') and
1683 not f.LocalPath().startswith('third_party/WebKit') and
1684 not f.LocalPath().startswith('third_party\\WebKit')):
1685 continue
1686
jbriance9e12f162016-11-25 07:57:501687 if not f.LocalPath().endswith('.h'):
1688 continue
1689
1690 contents = input_api.ReadFile(f)
1691 fwd_decls = input_api.re.findall(class_pattern, contents)
1692 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1693
1694 useless_fwd_decls = []
1695 for decl in fwd_decls:
1696 count = sum(1 for _ in input_api.re.finditer(
1697 r'\b%s\b' % input_api.re.escape(decl), contents))
1698 if count == 1:
1699 useless_fwd_decls.append(decl)
1700
1701 if not useless_fwd_decls:
1702 continue
1703
1704 for line in f.GenerateScmDiff().splitlines():
1705 if (line.startswith('-') and not line.startswith('--') or
1706 line.startswith('+') and not line.startswith('++')):
1707 for decl in useless_fwd_decls:
1708 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1709 results.append(output_api.PresubmitPromptWarning(
1710 '%s: %s forward declaration is becoming useless' %
1711 (f.LocalPath(), decl)))
1712 useless_fwd_decls.remove(decl)
1713
1714 return results
1715
1716
dskiba88634f4e2015-08-14 23:03:291717def _CheckAndroidToastUsage(input_api, output_api):
1718 """Checks that code uses org.chromium.ui.widget.Toast instead of
1719 android.widget.Toast (Chromium Toast doesn't force hardware
1720 acceleration on low-end devices, saving memory).
1721 """
1722 toast_import_pattern = input_api.re.compile(
1723 r'^import android\.widget\.Toast;$')
1724
1725 errors = []
1726
1727 sources = lambda affected_file: input_api.FilterSourceFile(
1728 affected_file,
1729 black_list=(_EXCLUDED_PATHS +
1730 _TEST_CODE_EXCLUDED_PATHS +
1731 input_api.DEFAULT_BLACK_LIST +
1732 (r'^chromecast[\\\/].*',
1733 r'^remoting[\\\/].*')),
1734 white_list=(r'.*\.java$',))
1735
1736 for f in input_api.AffectedSourceFiles(sources):
1737 for line_num, line in f.ChangedContents():
1738 if toast_import_pattern.search(line):
1739 errors.append("%s:%d" % (f.LocalPath(), line_num))
1740
1741 results = []
1742
1743 if errors:
1744 results.append(output_api.PresubmitError(
1745 'android.widget.Toast usage is detected. Android toasts use hardware'
1746 ' acceleration, and can be\ncostly on low-end devices. Please use'
1747 ' org.chromium.ui.widget.Toast instead.\n'
1748 'Contact [email protected] if you have any questions.',
1749 errors))
1750
1751 return results
1752
1753
dgnaa68d5e2015-06-10 10:08:221754def _CheckAndroidCrLogUsage(input_api, output_api):
1755 """Checks that new logs using org.chromium.base.Log:
1756 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511757 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221758 """
pkotwicza1dd0b002016-05-16 14:41:041759
torne89540622017-03-24 19:41:301760 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041761 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301762 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041763 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301764 # WebView license viewer code cannot depend on //base; used in stub APK.
1765 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1766 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041767 ]
1768
dgnaa68d5e2015-06-10 10:08:221769 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121770 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1771 class_in_base_pattern = input_api.re.compile(
1772 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1773 has_some_log_import_pattern = input_api.re.compile(
1774 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221775 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121776 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221777 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511778 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221779 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221780
Vincent Scheib16d7b272015-09-15 18:09:071781 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221782 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041783 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1784 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121785
dgnaa68d5e2015-06-10 10:08:221786 tag_decl_errors = []
1787 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121788 tag_errors = []
dgn38736db2015-09-18 19:20:511789 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121790 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221791
1792 for f in input_api.AffectedSourceFiles(sources):
1793 file_content = input_api.ReadFile(f)
1794 has_modified_logs = False
1795
1796 # Per line checks
dgn87d9fb62015-06-12 09:15:121797 if (cr_log_import_pattern.search(file_content) or
1798 (class_in_base_pattern.search(file_content) and
1799 not has_some_log_import_pattern.search(file_content))):
1800 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221801 for line_num, line in f.ChangedContents():
1802
1803 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121804 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221805 if match:
1806 has_modified_logs = True
1807
1808 # Make sure it uses "TAG"
1809 if not match.group('tag') == 'TAG':
1810 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121811 else:
1812 # Report non cr Log function calls in changed lines
1813 for line_num, line in f.ChangedContents():
1814 if log_call_pattern.search(line):
1815 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221816
1817 # Per file checks
1818 if has_modified_logs:
1819 # Make sure the tag is using the "cr" prefix and is not too long
1820 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511821 tag_name = match.group('name') if match else None
1822 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221823 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511824 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221825 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511826 elif '.' in tag_name:
1827 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221828
1829 results = []
1830 if tag_decl_errors:
1831 results.append(output_api.PresubmitPromptWarning(
1832 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511833 '"private static final String TAG = "<package tag>".\n'
1834 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221835 tag_decl_errors))
1836
1837 if tag_length_errors:
1838 results.append(output_api.PresubmitError(
1839 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511840 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221841 tag_length_errors))
1842
1843 if tag_errors:
1844 results.append(output_api.PresubmitPromptWarning(
1845 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1846 tag_errors))
1847
dgn87d9fb62015-06-12 09:15:121848 if util_log_errors:
dgn4401aa52015-04-29 16:26:171849 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121850 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1851 util_log_errors))
1852
dgn38736db2015-09-18 19:20:511853 if tag_with_dot_errors:
1854 results.append(output_api.PresubmitPromptWarning(
1855 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1856 tag_with_dot_errors))
1857
dgn4401aa52015-04-29 16:26:171858 return results
1859
1860
yolandyan45001472016-12-21 21:12:421861def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1862 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1863 deprecated_annotation_import_pattern = input_api.re.compile(
1864 r'^import android\.test\.suitebuilder\.annotation\..*;',
1865 input_api.re.MULTILINE)
1866 sources = lambda x: input_api.FilterSourceFile(
1867 x, white_list=(r'.*\.java$',), black_list=None)
1868 errors = []
1869 for f in input_api.AffectedFiles(sources):
1870 for line_num, line in f.ChangedContents():
1871 if deprecated_annotation_import_pattern.search(line):
1872 errors.append("%s:%d" % (f.LocalPath(), line_num))
1873
1874 results = []
1875 if errors:
1876 results.append(output_api.PresubmitError(
1877 'Annotations in android.test.suitebuilder.annotation have been'
1878 ' deprecated since API level 24. Please use android.support.test.filters'
1879 ' from //third_party/android_support_test_runner:runner_java instead.'
1880 ' Contact [email protected] if you have any questions.', errors))
1881 return results
1882
1883
agrieve7b6479d82015-10-07 14:24:221884def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1885 """Checks if MDPI assets are placed in a correct directory."""
1886 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1887 ('/res/drawable/' in f.LocalPath() or
1888 '/res/drawable-ldrtl/' in f.LocalPath()))
1889 errors = []
1890 for f in input_api.AffectedFiles(include_deletes=False,
1891 file_filter=file_filter):
1892 errors.append(' %s' % f.LocalPath())
1893
1894 results = []
1895 if errors:
1896 results.append(output_api.PresubmitError(
1897 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1898 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1899 '/res/drawable-ldrtl/.\n'
1900 'Contact [email protected] if you have questions.', errors))
1901 return results
1902
1903
agrievef32bcc72016-04-04 14:57:401904class PydepsChecker(object):
1905 def __init__(self, input_api, pydeps_files):
1906 self._file_cache = {}
1907 self._input_api = input_api
1908 self._pydeps_files = pydeps_files
1909
1910 def _LoadFile(self, path):
1911 """Returns the list of paths within a .pydeps file relative to //."""
1912 if path not in self._file_cache:
1913 with open(path) as f:
1914 self._file_cache[path] = f.read()
1915 return self._file_cache[path]
1916
1917 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1918 """Returns an interable of paths within the .pydep, relativized to //."""
1919 os_path = self._input_api.os_path
1920 pydeps_dir = os_path.dirname(pydeps_path)
1921 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1922 if not l.startswith('*'))
1923 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1924
1925 def _CreateFilesToPydepsMap(self):
1926 """Returns a map of local_path -> list_of_pydeps."""
1927 ret = {}
1928 for pydep_local_path in self._pydeps_files:
1929 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1930 ret.setdefault(path, []).append(pydep_local_path)
1931 return ret
1932
1933 def ComputeAffectedPydeps(self):
1934 """Returns an iterable of .pydeps files that might need regenerating."""
1935 affected_pydeps = set()
1936 file_to_pydeps_map = None
1937 for f in self._input_api.AffectedFiles(include_deletes=True):
1938 local_path = f.LocalPath()
1939 if local_path == 'DEPS':
1940 return self._pydeps_files
1941 elif local_path.endswith('.pydeps'):
1942 if local_path in self._pydeps_files:
1943 affected_pydeps.add(local_path)
1944 elif local_path.endswith('.py'):
1945 if file_to_pydeps_map is None:
1946 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1947 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1948 return affected_pydeps
1949
1950 def DetermineIfStale(self, pydeps_path):
1951 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411952 import difflib
agrievef32bcc72016-04-04 14:57:401953 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1954 cmd = old_pydeps_data[1][1:].strip()
1955 new_pydeps_data = self._input_api.subprocess.check_output(
1956 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411957 old_contents = old_pydeps_data[2:]
1958 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401959 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411960 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401961
1962
1963def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1964 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001965 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281966 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1967 # Mac, so skip it on other platforms.
1968 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001969 return []
agrievef32bcc72016-04-04 14:57:401970 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1971 is_android = input_api.os_path.exists('third_party/android_tools')
1972 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1973 results = []
1974 # First, check for new / deleted .pydeps.
1975 for f in input_api.AffectedFiles(include_deletes=True):
1976 if f.LocalPath().endswith('.pydeps'):
1977 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1978 results.append(output_api.PresubmitError(
1979 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1980 'remove %s' % f.LocalPath()))
1981 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1982 results.append(output_api.PresubmitError(
1983 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1984 'include %s' % f.LocalPath()))
1985
1986 if results:
1987 return results
1988
1989 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1990
1991 for pydep_path in checker.ComputeAffectedPydeps():
1992 try:
phajdan.jr0d9878552016-11-04 10:49:411993 result = checker.DetermineIfStale(pydep_path)
1994 if result:
1995 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401996 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411997 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1998 'To regenerate, run:\n\n %s' %
1999 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402000 except input_api.subprocess.CalledProcessError as error:
2001 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2002 long_text=error.output)]
2003
2004 return results
2005
2006
glidere61efad2015-02-18 17:39:432007def _CheckSingletonInHeaders(input_api, output_api):
2008 """Checks to make sure no header files have |Singleton<|."""
2009 def FileFilter(affected_file):
2010 # It's ok for base/memory/singleton.h to have |Singleton<|.
2011 black_list = (_EXCLUDED_PATHS +
2012 input_api.DEFAULT_BLACK_LIST +
2013 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
2014 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2015
sergeyu34d21222015-09-16 00:11:442016 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432017 files = []
2018 for f in input_api.AffectedSourceFiles(FileFilter):
2019 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2020 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2021 contents = input_api.ReadFile(f)
2022 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242023 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432024 pattern.search(line)):
2025 files.append(f)
2026 break
2027
2028 if files:
yolandyandaabc6d2016-04-18 18:29:392029 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442030 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432031 'Please move them to an appropriate source file so that the ' +
2032 'template gets instantiated in a single compilation unit.',
2033 files) ]
2034 return []
2035
2036
dbeam1ec68ac2016-12-15 05:22:242037def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:202038 """Checks for old style compiled_resources.gyp files."""
2039 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
2040
2041 added_compiled_resources = filter(is_compiled_resource, [
2042 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
2043 ])
2044
2045 if not added_compiled_resources:
2046 return []
2047
2048 return [output_api.PresubmitError(
2049 "Found new compiled_resources.gyp files:\n%s\n\n"
2050 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:552051 "please use compiled_resources2.gyp instead:\n"
2052 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
2053 %
dbeam37e8e7402016-02-10 22:58:202054 "\n".join(added_compiled_resources))]
2055
2056
[email protected]fd20b902014-05-09 02:14:532057_DEPRECATED_CSS = [
2058 # Values
2059 ( "-webkit-box", "flex" ),
2060 ( "-webkit-inline-box", "inline-flex" ),
2061 ( "-webkit-flex", "flex" ),
2062 ( "-webkit-inline-flex", "inline-flex" ),
2063 ( "-webkit-min-content", "min-content" ),
2064 ( "-webkit-max-content", "max-content" ),
2065
2066 # Properties
2067 ( "-webkit-background-clip", "background-clip" ),
2068 ( "-webkit-background-origin", "background-origin" ),
2069 ( "-webkit-background-size", "background-size" ),
2070 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442071 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532072
2073 # Functions
2074 ( "-webkit-gradient", "gradient" ),
2075 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2076 ( "-webkit-linear-gradient", "linear-gradient" ),
2077 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2078 ( "-webkit-radial-gradient", "radial-gradient" ),
2079 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2080]
2081
dbeam1ec68ac2016-12-15 05:22:242082def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532083 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252084 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342085 documentation and iOS CSS for dom distiller
2086 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252087 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532088 results = []
dbeam070cfe62014-10-22 06:44:022089 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252090 black_list = (_EXCLUDED_PATHS +
2091 _TEST_CODE_EXCLUDED_PATHS +
2092 input_api.DEFAULT_BLACK_LIST +
2093 (r"^chrome/common/extensions/docs",
2094 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342095 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052096 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442097 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252098 r"^native_client_sdk"))
2099 file_filter = lambda f: input_api.FilterSourceFile(
2100 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532101 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2102 for line_num, line in fpath.ChangedContents():
2103 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022104 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532105 results.append(output_api.PresubmitError(
2106 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2107 (fpath.LocalPath(), line_num, deprecated_value, value)))
2108 return results
2109
mohan.reddyf21db962014-10-16 12:26:472110
dbeam070cfe62014-10-22 06:44:022111_DEPRECATED_JS = [
2112 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2113 ( "__defineGetter__", "Object.defineProperty" ),
2114 ( "__defineSetter__", "Object.defineProperty" ),
2115]
2116
dbeam1ec68ac2016-12-15 05:22:242117def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022118 """Make sure that we don't use deprecated JS in Chrome code."""
2119 results = []
2120 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2121 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2122 input_api.DEFAULT_BLACK_LIST)
2123 file_filter = lambda f: input_api.FilterSourceFile(
2124 f, white_list=file_inclusion_pattern, black_list=black_list)
2125 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2126 for lnum, line in fpath.ChangedContents():
2127 for (deprecated, replacement) in _DEPRECATED_JS:
2128 if deprecated in line:
2129 results.append(output_api.PresubmitError(
2130 "%s:%d: Use of deprecated JS %s, use %s instead" %
2131 (fpath.LocalPath(), lnum, deprecated, replacement)))
2132 return results
2133
2134
dbeam1ec68ac2016-12-15 05:22:242135def _CheckForRiskyJsFeatures(input_api, output_api):
2136 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2137 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2138
2139 arrow_lines = []
2140 for f in input_api.AffectedFiles(file_filter=file_filter):
2141 for lnum, line in f.ChangedContents():
2142 if ' => ' in line:
2143 arrow_lines.append((f.LocalPath(), lnum))
2144
2145 if not arrow_lines:
2146 return []
2147
2148 return [output_api.PresubmitPromptWarning("""
2149Use of => operator detected in:
2150%s
2151Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2152https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2153""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2154
2155
dgnaa68d5e2015-06-10 10:08:222156def _AndroidSpecificOnUploadChecks(input_api, output_api):
2157 """Groups checks that target android code."""
2158 results = []
dgnaa68d5e2015-06-10 10:08:222159 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222160 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292161 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422162 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222163 return results
2164
2165
[email protected]22c9bd72011-03-27 16:47:392166def _CommonChecks(input_api, output_api):
2167 """Checks common to both upload and commit."""
2168 results = []
2169 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382170 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542171 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582172 results.extend(
2173 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192174 results.extend(
[email protected]760deea2013-12-10 19:33:492175 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542176 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182177 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522178 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222179 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442180 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592181 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062182 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122183 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182184 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222185 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302186 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492187 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272188 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032189 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492190 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442191 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272192 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542193 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442194 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392195 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552196 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042197 results.extend(
2198 input_api.canned_checks.CheckChangeHasNoTabs(
2199 input_api,
2200 output_api,
2201 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402202 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162203 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592204 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082205 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242206 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2207 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472208 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042209 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232210 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432211 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242212 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402213 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152214 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172215 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502216 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242217 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242218
2219 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2220 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2221 input_api, output_api,
2222 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382223 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392224 return results
[email protected]1f7b4172010-01-28 01:17:342225
[email protected]b337cb5b2011-01-23 21:24:052226
[email protected]b8079ae4a2012-12-05 19:56:492227def _CheckPatchFiles(input_api, output_api):
2228 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2229 if f.LocalPath().endswith(('.orig', '.rej'))]
2230 if problems:
2231 return [output_api.PresubmitError(
2232 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032233 else:
2234 return []
[email protected]b8079ae4a2012-12-05 19:56:492235
2236
[email protected]b00342e7f2013-03-26 16:21:542237def _DidYouMeanOSMacro(bad_macro):
2238 try:
2239 return {'A': 'OS_ANDROID',
2240 'B': 'OS_BSD',
2241 'C': 'OS_CHROMEOS',
2242 'F': 'OS_FREEBSD',
2243 'L': 'OS_LINUX',
2244 'M': 'OS_MACOSX',
2245 'N': 'OS_NACL',
2246 'O': 'OS_OPENBSD',
2247 'P': 'OS_POSIX',
2248 'S': 'OS_SOLARIS',
2249 'W': 'OS_WIN'}[bad_macro[3].upper()]
2250 except KeyError:
2251 return ''
2252
2253
2254def _CheckForInvalidOSMacrosInFile(input_api, f):
2255 """Check for sensible looking, totally invalid OS macros."""
2256 preprocessor_statement = input_api.re.compile(r'^\s*#')
2257 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2258 results = []
2259 for lnum, line in f.ChangedContents():
2260 if preprocessor_statement.search(line):
2261 for match in os_macro.finditer(line):
2262 if not match.group(1) in _VALID_OS_MACROS:
2263 good = _DidYouMeanOSMacro(match.group(1))
2264 did_you_mean = ' (did you mean %s?)' % good if good else ''
2265 results.append(' %s:%d %s%s' % (f.LocalPath(),
2266 lnum,
2267 match.group(1),
2268 did_you_mean))
2269 return results
2270
2271
2272def _CheckForInvalidOSMacros(input_api, output_api):
2273 """Check all affected files for invalid OS macros."""
2274 bad_macros = []
2275 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472276 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542277 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2278
2279 if not bad_macros:
2280 return []
2281
2282 return [output_api.PresubmitError(
2283 'Possibly invalid OS macro[s] found. Please fix your code\n'
2284 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2285
lliabraa35bab3932014-10-01 12:16:442286
2287def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2288 """Check all affected files for invalid "if defined" macros."""
2289 ALWAYS_DEFINED_MACROS = (
2290 "TARGET_CPU_PPC",
2291 "TARGET_CPU_PPC64",
2292 "TARGET_CPU_68K",
2293 "TARGET_CPU_X86",
2294 "TARGET_CPU_ARM",
2295 "TARGET_CPU_MIPS",
2296 "TARGET_CPU_SPARC",
2297 "TARGET_CPU_ALPHA",
2298 "TARGET_IPHONE_SIMULATOR",
2299 "TARGET_OS_EMBEDDED",
2300 "TARGET_OS_IPHONE",
2301 "TARGET_OS_MAC",
2302 "TARGET_OS_UNIX",
2303 "TARGET_OS_WIN32",
2304 )
2305 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2306 results = []
2307 for lnum, line in f.ChangedContents():
2308 for match in ifdef_macro.finditer(line):
2309 if match.group(1) in ALWAYS_DEFINED_MACROS:
2310 always_defined = ' %s is always defined. ' % match.group(1)
2311 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2312 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2313 lnum,
2314 always_defined,
2315 did_you_mean))
2316 return results
2317
2318
2319def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2320 """Check all affected files for invalid "if defined" macros."""
2321 bad_macros = []
2322 for f in input_api.AffectedFiles():
2323 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2324 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2325
2326 if not bad_macros:
2327 return []
2328
2329 return [output_api.PresubmitError(
2330 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2331 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2332 bad_macros)]
2333
2334
mlamouria82272622014-09-16 18:45:042335def _CheckForIPCRules(input_api, output_api):
2336 """Check for same IPC rules described in
2337 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2338 """
2339 base_pattern = r'IPC_ENUM_TRAITS\('
2340 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2341 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2342
2343 problems = []
2344 for f in input_api.AffectedSourceFiles(None):
2345 local_path = f.LocalPath()
2346 if not local_path.endswith('.h'):
2347 continue
2348 for line_number, line in f.ChangedContents():
2349 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2350 problems.append(
2351 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2352
2353 if problems:
2354 return [output_api.PresubmitPromptWarning(
2355 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2356 else:
2357 return []
2358
[email protected]b00342e7f2013-03-26 16:21:542359
mostynbb639aca52015-01-07 20:31:232360def _CheckForWindowsLineEndings(input_api, output_api):
2361 """Check source code and known ascii text files for Windows style line
2362 endings.
2363 """
earthdok1b5e0ee2015-03-10 15:19:102364 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232365
2366 file_inclusion_pattern = (
2367 known_text_files,
2368 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2369 )
2370
2371 filter = lambda f: input_api.FilterSourceFile(
2372 f, white_list=file_inclusion_pattern, black_list=None)
2373 files = [f.LocalPath() for f in
2374 input_api.AffectedSourceFiles(filter)]
2375
2376 problems = []
2377
2378 for file in files:
2379 fp = open(file, 'r')
2380 for line in fp:
2381 if line.endswith('\r\n'):
2382 problems.append(file)
2383 break
2384 fp.close()
2385
2386 if problems:
2387 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2388 'these files to contain Windows style line endings?\n' +
2389 '\n'.join(problems))]
2390
2391 return []
2392
2393
pastarmovj89f7ee12016-09-20 14:58:132394def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2395 lint_filters=None, verbose_level=None):
2396 """Checks that all source files use SYSLOG properly."""
2397 syslog_files = []
2398 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562399 for line_number, line in f.ChangedContents():
2400 if 'SYSLOG' in line:
2401 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2402
pastarmovj89f7ee12016-09-20 14:58:132403 if syslog_files:
2404 return [output_api.PresubmitPromptWarning(
2405 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2406 ' calls.\nFiles to check:\n', items=syslog_files)]
2407 return []
2408
2409
[email protected]1f7b4172010-01-28 01:17:342410def CheckChangeOnUpload(input_api, output_api):
2411 results = []
2412 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472413 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282414 results.extend(
jam93a6ee792017-02-08 23:59:222415 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192416 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222417 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132418 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162419 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542420 return results
[email protected]ca8d19842009-02-19 16:33:122421
2422
[email protected]1bfb8322014-04-23 01:02:412423def GetTryServerMasterForBot(bot):
2424 """Returns the Try Server master for the given bot.
2425
[email protected]0bb112362014-07-26 04:38:322426 It tries to guess the master from the bot name, but may still fail
2427 and return None. There is no longer a default master.
2428 """
2429 # Potentially ambiguous bot names are listed explicitly.
2430 master_map = {
tandriie5587792016-07-14 00:34:502431 'chromium_presubmit': 'master.tryserver.chromium.linux',
2432 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412433 }
[email protected]0bb112362014-07-26 04:38:322434 master = master_map.get(bot)
2435 if not master:
wnwen4fbaab82016-05-25 12:54:362436 if 'android' in bot:
tandriie5587792016-07-14 00:34:502437 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362438 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502439 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322440 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502441 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322442 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502443 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322444 return master
[email protected]1bfb8322014-04-23 01:02:412445
2446
Paweł Hajdan, Jr55083782014-12-19 20:32:562447def GetDefaultTryConfigs(bots):
2448 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012449 """
2450
Paweł Hajdan, Jr55083782014-12-19 20:32:562451 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412452
2453 # Build up the mapping from tryserver master to bot/test.
2454 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562455 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412456 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2457 return out
[email protected]38c6a512013-12-18 23:48:012458
2459
[email protected]ca8d19842009-02-19 16:33:122460def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542461 results = []
[email protected]1f7b4172010-01-28 01:17:342462 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542463 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272464 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342465 input_api,
2466 output_api,
[email protected]2fdd1f362013-01-16 03:56:032467 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272468
jam93a6ee792017-02-08 23:59:222469 results.extend(
2470 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542471 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2472 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412473 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2474 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542475 return results