blob: ca87ae7d45b7894c5031a142ac1b7dcb10b24129 [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",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# 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,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|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]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d19842009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[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 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
kmarshallbb619532016-01-29 21:24:49169 r"^blimp[\\\/]engine[\\\/]app[\\\/]blimp_browser_main_parts\.cc$",
tfarina0923ac52015-01-07 03:21:22170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31171 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51172 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
173 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09174 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49175 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
176 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41177 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
178 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48179 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
180 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01181 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54182 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
joedow91151042016-02-08 21:18:13183 r"^remoting[\\\/]host[\\\/]security_key[\\\/]"
184 "gnubby_auth_handler_linux\.cc$",
dnicoara171d8c82015-03-05 20:46:18185 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
rjkroege8471a0a92016-02-04 19:50:29186 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49187 ),
[email protected]23e6cbc2012-06-16 18:51:20188 ),
[email protected]52657f62013-05-20 05:30:31189 (
190 'SkRefPtr',
191 (
192 'The use of SkRefPtr is prohibited. ',
193 'Please use skia::RefPtr instead.'
194 ),
195 True,
196 (),
197 ),
198 (
199 'SkAutoRef',
200 (
201 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
202 'Please use skia::RefPtr instead.'
203 ),
204 True,
205 (),
206 ),
207 (
208 'SkAutoTUnref',
209 (
210 'The use of SkAutoTUnref is dangerous because it implicitly ',
211 'converts to a raw pointer. Please use skia::RefPtr instead.'
212 ),
213 True,
214 (),
215 ),
216 (
217 'SkAutoUnref',
218 (
219 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
220 'because it implicitly converts to a raw pointer. ',
221 'Please use skia::RefPtr instead.'
222 ),
223 True,
224 (),
225 ),
[email protected]d89eec82013-12-03 14:10:59226 (
227 r'/HANDLE_EINTR\(.*close',
228 (
229 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
230 'descriptor will be closed, and it is incorrect to retry the close.',
231 'Either call close directly and ignore its return value, or wrap close',
232 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
233 ),
234 True,
235 (),
236 ),
237 (
238 r'/IGNORE_EINTR\((?!.*close)',
239 (
240 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
241 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
242 ),
243 True,
244 (
245 # Files that #define IGNORE_EINTR.
246 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
247 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
248 ),
249 ),
[email protected]ec5b3f02014-04-04 18:43:43250 (
251 r'/v8::Extension\(',
252 (
253 'Do not introduce new v8::Extensions into the code base, use',
254 'gin::Wrappable instead. See http://crbug.com/334679',
255 ),
256 True,
[email protected]f55c90ee62014-04-12 00:50:03257 (
joaodasilva718f87672014-08-30 09:25:49258 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03259 ),
[email protected]ec5b3f02014-04-04 18:43:43260 ),
skyostilf9469f72015-04-20 10:38:52261 (
sdefresneeaeccc52015-04-22 08:18:32262 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52263 (
264 'MessageLoopProxy is deprecated. ',
265 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
266 ),
267 True,
kinuko59024ce2015-04-21 22:18:30268 (
269 # Internal message_loop related code may still use it.
270 r'^base[\\\/]message_loop[\\\/].*',
271 ),
skyostilf9469f72015-04-20 10:38:52272 ),
jame2d1a952016-04-02 00:27:10273 (
274 '#pragma comment(lib,',
275 (
276 'Specify libraries to link with in build files and not in the source.',
277 ),
278 True,
279 (),
280 ),
[email protected]127f18ec2012-06-16 05:05:59281)
282
mlamouria82272622014-09-16 18:45:04283_IPC_ENUM_TRAITS_DEPRECATED = (
284 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
285 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
286
[email protected]127f18ec2012-06-16 05:05:59287
[email protected]b00342e7f2013-03-26 16:21:54288_VALID_OS_MACROS = (
289 # Please keep sorted.
290 'OS_ANDROID',
291 'OS_BSD',
292 'OS_CAT', # For testing.
293 'OS_CHROMEOS',
294 'OS_FREEBSD',
295 'OS_IOS',
296 'OS_LINUX',
297 'OS_MACOSX',
298 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21299 'OS_NACL_NONSFI',
300 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54301 'OS_OPENBSD',
302 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37303 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54304 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54305 'OS_WIN',
306)
307
308
agrievef32bcc72016-04-04 14:57:40309_ANDROID_SPECIFIC_PYDEPS_FILES = [
310 'build/android/test_runner.pydeps',
311]
312
313_GENERIC_PYDEPS_FILES = [
314 'build/secondary/tools/swarming_client/isolate.pydeps',
315]
316
317_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
318
319
[email protected]55459852011-08-10 15:17:19320def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
321 """Attempts to prevent use of functions intended only for testing in
322 non-testing code. For now this is just a best-effort implementation
323 that ignores header files and may have some false positives. A
324 better implementation would probably need a proper C++ parser.
325 """
326 # We only scan .cc files and the like, as the declaration of
327 # for-testing functions in header files are hard to distinguish from
328 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44329 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19330
jochenc0d4808c2015-07-27 09:25:42331 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19332 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09333 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19334 exclusion_pattern = input_api.re.compile(
335 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
336 base_function_pattern, base_function_pattern))
337
338 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44339 black_list = (_EXCLUDED_PATHS +
340 _TEST_CODE_EXCLUDED_PATHS +
341 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19342 return input_api.FilterSourceFile(
343 affected_file,
344 white_list=(file_inclusion_pattern, ),
345 black_list=black_list)
346
347 problems = []
348 for f in input_api.AffectedSourceFiles(FilterFile):
349 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24350 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03351 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46352 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03353 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19354 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03355 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19356
357 if problems:
[email protected]f7051d52013-04-02 18:31:42358 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03359 else:
360 return []
[email protected]55459852011-08-10 15:17:19361
362
[email protected]10689ca2011-09-02 02:31:54363def _CheckNoIOStreamInHeaders(input_api, output_api):
364 """Checks to make sure no .h files include <iostream>."""
365 files = []
366 pattern = input_api.re.compile(r'^#include\s*<iostream>',
367 input_api.re.MULTILINE)
368 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
369 if not f.LocalPath().endswith('.h'):
370 continue
371 contents = input_api.ReadFile(f)
372 if pattern.search(contents):
373 files.append(f)
374
375 if len(files):
yolandyandaabc6d2016-04-18 18:29:39376 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06377 'Do not #include <iostream> in header files, since it inserts static '
378 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54379 '#include <ostream>. See http://crbug.com/94794',
380 files) ]
381 return []
382
383
[email protected]72df4e782012-06-21 16:28:18384def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52385 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18386 problems = []
387 for f in input_api.AffectedFiles():
388 if (not f.LocalPath().endswith(('.cc', '.mm'))):
389 continue
390
391 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04392 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18393 problems.append(' %s:%d' % (f.LocalPath(), line_num))
394
395 if not problems:
396 return []
397 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
398 '\n'.join(problems))]
399
400
danakj61c1aa22015-10-26 19:55:52401def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
402 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
403 errors = []
404 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
405 input_api.re.MULTILINE)
406 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
407 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
408 continue
409 for lnum, line in f.ChangedContents():
410 if input_api.re.search(pattern, line):
411 errors.append(output_api.PresubmitError(
412 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
413 'DCHECK_IS_ON()", not forgetting the braces.')
414 % (f.LocalPath(), lnum)))
415 return errors
416
417
mcasasb7440c282015-02-04 14:52:19418def _FindHistogramNameInLine(histogram_name, line):
419 """Tries to find a histogram name or prefix in a line."""
420 if not "affected-histogram" in line:
421 return histogram_name in line
422 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
423 # the histogram_name.
424 if not '"' in line:
425 return False
426 histogram_prefix = line.split('\"')[1]
427 return histogram_prefix in histogram_name
428
429
430def _CheckUmaHistogramChanges(input_api, output_api):
431 """Check that UMA histogram names in touched lines can still be found in other
432 lines of the patch or in histograms.xml. Note that this check would not catch
433 the reverse: changes in histograms.xml not matched in the code itself."""
434 touched_histograms = []
435 histograms_xml_modifications = []
436 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
437 for f in input_api.AffectedFiles():
438 # If histograms.xml itself is modified, keep the modified lines for later.
439 if f.LocalPath().endswith(('histograms.xml')):
440 histograms_xml_modifications = f.ChangedContents()
441 continue
442 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
443 continue
444 for line_num, line in f.ChangedContents():
445 found = pattern.search(line)
446 if found:
447 touched_histograms.append([found.group(1), f, line_num])
448
449 # Search for the touched histogram names in the local modifications to
450 # histograms.xml, and, if not found, on the base histograms.xml file.
451 unmatched_histograms = []
452 for histogram_info in touched_histograms:
453 histogram_name_found = False
454 for line_num, line in histograms_xml_modifications:
455 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
456 if histogram_name_found:
457 break
458 if not histogram_name_found:
459 unmatched_histograms.append(histogram_info)
460
eromanb90c82e7e32015-04-01 15:13:49461 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19462 problems = []
463 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49464 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19465 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45466 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19467 histogram_name_found = False
468 for line in histograms_xml:
469 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
470 if histogram_name_found:
471 break
472 if not histogram_name_found:
473 problems.append(' [%s:%d] %s' %
474 (f.LocalPath(), line_num, histogram_name))
475
476 if not problems:
477 return []
478 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
479 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49480 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19481
yolandyandaabc6d2016-04-18 18:29:39482def _CheckFlakyTestUsage(input_api, output_api):
483 """Check that FlakyTest annotation is our own instead of the android one"""
484 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
485 files = []
486 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
487 if f.LocalPath().endswith('Test.java'):
488 if pattern.search(input_api.ReadFile(f)):
489 files.append(f)
490 if len(files):
491 return [output_api.PresubmitError(
492 'Use org.chromium.base.test.util.FlakyTest instead of '
493 'android.test.FlakyTest',
494 files)]
495 return []
mcasasb7440c282015-02-04 14:52:19496
[email protected]8ea5d4b2011-09-13 21:49:22497def _CheckNoNewWStrings(input_api, output_api):
498 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27499 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22500 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20501 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57502 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
503 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20504 continue
[email protected]8ea5d4b2011-09-13 21:49:22505
[email protected]a11dbe9b2012-08-07 01:32:58506 allowWString = False
[email protected]b5c24292011-11-28 14:38:20507 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58508 if 'presubmit: allow wstring' in line:
509 allowWString = True
510 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27511 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58512 allowWString = False
513 else:
514 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22515
[email protected]55463aa62011-10-12 00:48:27516 if not problems:
517 return []
518 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58519 ' If you are calling a cross-platform API that accepts a wstring, '
520 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27521 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22522
523
[email protected]2a8ac9c2011-10-19 17:20:44524def _CheckNoDEPSGIT(input_api, output_api):
525 """Make sure .DEPS.git is never modified manually."""
526 if any(f.LocalPath().endswith('.DEPS.git') for f in
527 input_api.AffectedFiles()):
528 return [output_api.PresubmitError(
529 'Never commit changes to .DEPS.git. This file is maintained by an\n'
530 'automated system based on what\'s in DEPS and your changes will be\n'
531 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34532 '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:44533 'for more information')]
534 return []
535
536
tandriief664692014-09-23 14:51:47537def _CheckValidHostsInDEPS(input_api, output_api):
538 """Checks that DEPS file deps are from allowed_hosts."""
539 # Run only if DEPS file has been modified to annoy fewer bystanders.
540 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
541 return []
542 # Outsource work to gclient verify
543 try:
544 input_api.subprocess.check_output(['gclient', 'verify'])
545 return []
546 except input_api.subprocess.CalledProcessError, error:
547 return [output_api.PresubmitError(
548 'DEPS file must have only git dependencies.',
549 long_text=error.output)]
550
551
[email protected]127f18ec2012-06-16 05:05:59552def _CheckNoBannedFunctions(input_api, output_api):
553 """Make sure that banned functions are not used."""
554 warnings = []
555 errors = []
556
557 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
558 for f in input_api.AffectedFiles(file_filter=file_filter):
559 for line_num, line in f.ChangedContents():
560 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26561 matched = False
562 if func_name[0:1] == '/':
563 regex = func_name[1:]
564 if input_api.re.search(regex, line):
565 matched = True
566 elif func_name in line:
567 matched = True
568 if matched:
[email protected]127f18ec2012-06-16 05:05:59569 problems = warnings;
570 if error:
571 problems = errors;
572 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
573 for message_line in message:
574 problems.append(' %s' % message_line)
575
576 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
577 for f in input_api.AffectedFiles(file_filter=file_filter):
578 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49579 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
580 def IsBlacklisted(affected_file, blacklist):
581 local_path = affected_file.LocalPath()
582 for item in blacklist:
583 if input_api.re.match(item, local_path):
584 return True
585 return False
586 if IsBlacklisted(f, excluded_paths):
587 continue
[email protected]d89eec82013-12-03 14:10:59588 matched = False
589 if func_name[0:1] == '/':
590 regex = func_name[1:]
591 if input_api.re.search(regex, line):
592 matched = True
593 elif func_name in line:
594 matched = True
595 if matched:
[email protected]127f18ec2012-06-16 05:05:59596 problems = warnings;
597 if error:
598 problems = errors;
599 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
600 for message_line in message:
601 problems.append(' %s' % message_line)
602
603 result = []
604 if (warnings):
605 result.append(output_api.PresubmitPromptWarning(
606 'Banned functions were used.\n' + '\n'.join(warnings)))
607 if (errors):
608 result.append(output_api.PresubmitError(
609 'Banned functions were used.\n' + '\n'.join(errors)))
610 return result
611
612
[email protected]6c063c62012-07-11 19:11:06613def _CheckNoPragmaOnce(input_api, output_api):
614 """Make sure that banned functions are not used."""
615 files = []
616 pattern = input_api.re.compile(r'^#pragma\s+once',
617 input_api.re.MULTILINE)
618 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
619 if not f.LocalPath().endswith('.h'):
620 continue
621 contents = input_api.ReadFile(f)
622 if pattern.search(contents):
623 files.append(f)
624
625 if files:
626 return [output_api.PresubmitError(
627 'Do not use #pragma once in header files.\n'
628 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
629 files)]
630 return []
631
[email protected]127f18ec2012-06-16 05:05:59632
[email protected]e7479052012-09-19 00:26:12633def _CheckNoTrinaryTrueFalse(input_api, output_api):
634 """Checks to make sure we don't introduce use of foo ? true : false."""
635 problems = []
636 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
637 for f in input_api.AffectedFiles():
638 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
639 continue
640
641 for line_num, line in f.ChangedContents():
642 if pattern.match(line):
643 problems.append(' %s:%d' % (f.LocalPath(), line_num))
644
645 if not problems:
646 return []
647 return [output_api.PresubmitPromptWarning(
648 'Please consider avoiding the "? true : false" pattern if possible.\n' +
649 '\n'.join(problems))]
650
651
[email protected]55f9f382012-07-31 11:02:18652def _CheckUnwantedDependencies(input_api, output_api):
653 """Runs checkdeps on #include statements added in this
654 change. Breaking - rules is an error, breaking ! rules is a
655 warning.
656 """
mohan.reddyf21db962014-10-16 12:26:47657 import sys
[email protected]55f9f382012-07-31 11:02:18658 # We need to wait until we have an input_api object and use this
659 # roundabout construct to import checkdeps because this file is
660 # eval-ed and thus doesn't have __file__.
661 original_sys_path = sys.path
662 try:
663 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47664 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18665 import checkdeps
666 from cpp_checker import CppChecker
667 from rules import Rule
668 finally:
669 # Restore sys.path to what it was before.
670 sys.path = original_sys_path
671
672 added_includes = []
673 for f in input_api.AffectedFiles():
674 if not CppChecker.IsCppFile(f.LocalPath()):
675 continue
676
677 changed_lines = [line for line_num, line in f.ChangedContents()]
678 added_includes.append([f.LocalPath(), changed_lines])
679
[email protected]26385172013-05-09 23:11:35680 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18681
682 error_descriptions = []
683 warning_descriptions = []
684 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
685 added_includes):
686 description_with_path = '%s\n %s' % (path, rule_description)
687 if rule_type == Rule.DISALLOW:
688 error_descriptions.append(description_with_path)
689 else:
690 warning_descriptions.append(description_with_path)
691
692 results = []
693 if error_descriptions:
694 results.append(output_api.PresubmitError(
695 'You added one or more #includes that violate checkdeps rules.',
696 error_descriptions))
697 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42698 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18699 'You added one or more #includes of files that are temporarily\n'
700 'allowed but being removed. Can you avoid introducing the\n'
701 '#include? See relevant DEPS file(s) for details and contacts.',
702 warning_descriptions))
703 return results
704
705
[email protected]fbcafe5a2012-08-08 15:31:22706def _CheckFilePermissions(input_api, output_api):
707 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15708 if input_api.platform == 'win32':
709 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29710 checkperms_tool = input_api.os_path.join(
711 input_api.PresubmitLocalPath(),
712 'tools', 'checkperms', 'checkperms.py')
713 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47714 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22715 for f in input_api.AffectedFiles():
716 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11717 try:
718 input_api.subprocess.check_output(args)
719 return []
720 except input_api.subprocess.CalledProcessError as error:
721 return [output_api.PresubmitError(
722 'checkperms.py failed:',
723 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22724
725
[email protected]c8278b32012-10-30 20:35:49726def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
727 """Makes sure we don't include ui/aura/window_property.h
728 in header files.
729 """
730 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
731 errors = []
732 for f in input_api.AffectedFiles():
733 if not f.LocalPath().endswith('.h'):
734 continue
735 for line_num, line in f.ChangedContents():
736 if pattern.match(line):
737 errors.append(' %s:%d' % (f.LocalPath(), line_num))
738
739 results = []
740 if errors:
741 results.append(output_api.PresubmitError(
742 'Header files should not include ui/aura/window_property.h', errors))
743 return results
744
745
[email protected]cf9b78f2012-11-14 11:40:28746def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
747 """Checks that the lines in scope occur in the right order.
748
749 1. C system files in alphabetical order
750 2. C++ system files in alphabetical order
751 3. Project's .h files
752 """
753
754 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
755 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
756 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
757
758 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
759
760 state = C_SYSTEM_INCLUDES
761
762 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57763 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28764 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55765 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28766 for line_num, line in scope:
767 if c_system_include_pattern.match(line):
768 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55769 problem_linenums.append((line_num, previous_line_num,
770 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28771 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55772 problem_linenums.append((line_num, previous_line_num,
773 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28774 elif cpp_system_include_pattern.match(line):
775 if state == C_SYSTEM_INCLUDES:
776 state = CPP_SYSTEM_INCLUDES
777 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55778 problem_linenums.append((line_num, previous_line_num,
779 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28780 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55781 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28782 elif custom_include_pattern.match(line):
783 if state != CUSTOM_INCLUDES:
784 state = CUSTOM_INCLUDES
785 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55786 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28787 else:
brucedawson70fadb02015-06-30 17:47:55788 problem_linenums.append((line_num, previous_line_num,
789 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28790 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57791 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28792
793 warnings = []
brucedawson70fadb02015-06-30 17:47:55794 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57795 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55796 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28797 return warnings
798
799
[email protected]ac294a12012-12-06 16:38:43800def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28801 """Checks the #include order for the given file f."""
802
[email protected]2299dcf2012-11-15 19:56:24803 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30804 # Exclude the following includes from the check:
805 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
806 # specific order.
807 # 2) <atlbase.h>, "build/build_config.h"
808 excluded_include_pattern = input_api.re.compile(
809 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24810 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33811 # Match the final or penultimate token if it is xxxtest so we can ignore it
812 # when considering the special first include.
813 test_file_tag_pattern = input_api.re.compile(
814 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11815 if_pattern = input_api.re.compile(
816 r'\s*#\s*(if|elif|else|endif|define|undef).*')
817 # Some files need specialized order of includes; exclude such files from this
818 # check.
819 uncheckable_includes_pattern = input_api.re.compile(
820 r'\s*#include '
821 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28822
823 contents = f.NewContents()
824 warnings = []
825 line_num = 0
826
[email protected]ac294a12012-12-06 16:38:43827 # Handle the special first include. If the first include file is
828 # some/path/file.h, the corresponding including file can be some/path/file.cc,
829 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
830 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33831 # If the included file is some/path/file_platform.h the including file could
832 # also be some/path/file_xxxtest_platform.h.
833 including_file_base_name = test_file_tag_pattern.sub(
834 '', input_api.os_path.basename(f.LocalPath()))
835
[email protected]ac294a12012-12-06 16:38:43836 for line in contents:
837 line_num += 1
838 if system_include_pattern.match(line):
839 # No special first include -> process the line again along with normal
840 # includes.
841 line_num -= 1
842 break
843 match = custom_include_pattern.match(line)
844 if match:
845 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33846 header_basename = test_file_tag_pattern.sub(
847 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
848
849 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24850 # No special first include -> process the line again along with normal
851 # includes.
852 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43853 break
[email protected]cf9b78f2012-11-14 11:40:28854
855 # Split into scopes: Each region between #if and #endif is its own scope.
856 scopes = []
857 current_scope = []
858 for line in contents[line_num:]:
859 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11860 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54861 continue
[email protected]2309b0fa02012-11-16 12:18:27862 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28863 scopes.append(current_scope)
864 current_scope = []
[email protected]962f117e2012-11-22 18:11:56865 elif ((system_include_pattern.match(line) or
866 custom_include_pattern.match(line)) and
867 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28868 current_scope.append((line_num, line))
869 scopes.append(current_scope)
870
871 for scope in scopes:
872 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
873 changed_linenums))
874 return warnings
875
876
877def _CheckIncludeOrder(input_api, output_api):
878 """Checks that the #include order is correct.
879
880 1. The corresponding header for source files.
881 2. C system files in alphabetical order
882 3. C++ system files in alphabetical order
883 4. Project's .h files in alphabetical order
884
[email protected]ac294a12012-12-06 16:38:43885 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
886 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28887 """
[email protected]e120b012014-08-15 19:08:35888 def FileFilterIncludeOrder(affected_file):
889 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
890 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28891
892 warnings = []
[email protected]e120b012014-08-15 19:08:35893 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08894 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43895 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
896 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28897
898 results = []
899 if warnings:
[email protected]f7051d52013-04-02 18:31:42900 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53901 warnings))
[email protected]cf9b78f2012-11-14 11:40:28902 return results
903
904
[email protected]70ca77752012-11-20 03:45:03905def _CheckForVersionControlConflictsInFile(input_api, f):
906 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
907 errors = []
908 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23909 if f.LocalPath().endswith('.md'):
910 # First-level headers in markdown look a lot like version control
911 # conflict markers. http://daringfireball.net/projects/markdown/basics
912 continue
[email protected]70ca77752012-11-20 03:45:03913 if pattern.match(line):
914 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
915 return errors
916
917
918def _CheckForVersionControlConflicts(input_api, output_api):
919 """Usually this is not intentional and will cause a compile failure."""
920 errors = []
921 for f in input_api.AffectedFiles():
922 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
923
924 results = []
925 if errors:
926 results.append(output_api.PresubmitError(
927 'Version control conflict markers found, please resolve.', errors))
928 return results
929
930
[email protected]06e6d0ff2012-12-11 01:36:44931def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
932 def FilterFile(affected_file):
933 """Filter function for use with input_api.AffectedSourceFiles,
934 below. This filters out everything except non-test files from
935 top-level directories that generally speaking should not hard-code
936 service URLs (e.g. src/android_webview/, src/content/ and others).
937 """
938 return input_api.FilterSourceFile(
939 affected_file,
[email protected]78bb39d62012-12-11 15:11:56940 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44941 black_list=(_EXCLUDED_PATHS +
942 _TEST_CODE_EXCLUDED_PATHS +
943 input_api.DEFAULT_BLACK_LIST))
944
reillyi38965732015-11-16 18:27:33945 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
946 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46947 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
948 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44949 problems = [] # items are (filename, line_number, line)
950 for f in input_api.AffectedSourceFiles(FilterFile):
951 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46952 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44953 problems.append((f.LocalPath(), line_num, line))
954
955 if problems:
[email protected]f7051d52013-04-02 18:31:42956 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44957 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58958 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44959 [' %s:%d: %s' % (
960 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03961 else:
962 return []
[email protected]06e6d0ff2012-12-11 01:36:44963
964
[email protected]d2530012013-01-25 16:39:27965def _CheckNoAbbreviationInPngFileName(input_api, output_api):
966 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31967 The native_client_sdk directory is excluded because it has auto-generated PNG
968 files for documentation.
[email protected]d2530012013-01-25 16:39:27969 """
[email protected]d2530012013-01-25 16:39:27970 errors = []
binji0dcdf342014-12-12 18:32:31971 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
972 black_list = (r'^native_client_sdk[\\\/]',)
973 file_filter = lambda f: input_api.FilterSourceFile(
974 f, white_list=white_list, black_list=black_list)
975 for f in input_api.AffectedFiles(include_deletes=False,
976 file_filter=file_filter):
977 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27978
979 results = []
980 if errors:
981 results.append(output_api.PresubmitError(
982 'The name of PNG files should not have abbreviations. \n'
983 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
984 'Contact [email protected] if you have questions.', errors))
985 return results
986
987
[email protected]14a6131c2014-01-08 01:15:41988def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08989 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41990 a set of DEPS entries that we should look up.
991
992 For a directory (rather than a specific filename) we fake a path to
993 a specific filename by adding /DEPS. This is chosen as a file that
994 will seldom or never be subject to per-file include_rules.
995 """
[email protected]2b438d62013-11-14 17:54:14996 # We ignore deps entries on auto-generated directories.
997 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08998
999 # This pattern grabs the path without basename in the first
1000 # parentheses, and the basename (if present) in the second. It
1001 # relies on the simple heuristic that if there is a basename it will
1002 # be a header file ending in ".h".
1003 pattern = re.compile(
1004 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141005 results = set()
[email protected]f32e2d1e2013-07-26 21:39:081006 for changed_line in changed_lines:
1007 m = pattern.match(changed_line)
1008 if m:
1009 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:141010 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:411011 if m.group(2):
1012 results.add('%s%s' % (path, m.group(2)))
1013 else:
1014 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081015 return results
1016
1017
[email protected]e871964c2013-05-13 14:14:551018def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1019 """When a dependency prefixed with + is added to a DEPS file, we
1020 want to make sure that the change is reviewed by an OWNER of the
1021 target file or directory, to avoid layering violations from being
1022 introduced. This check verifies that this happens.
1023 """
1024 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241025
1026 file_filter = lambda f: not input_api.re.match(
1027 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1028 for f in input_api.AffectedFiles(include_deletes=False,
1029 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551030 filename = input_api.os_path.basename(f.LocalPath())
1031 if filename == 'DEPS':
1032 changed_lines |= set(line.strip()
1033 for line_num, line
1034 in f.ChangedContents())
1035 if not changed_lines:
1036 return []
1037
[email protected]14a6131c2014-01-08 01:15:411038 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1039 changed_lines)
[email protected]e871964c2013-05-13 14:14:551040 if not virtual_depended_on_files:
1041 return []
1042
1043 if input_api.is_committing:
1044 if input_api.tbr:
1045 return [output_api.PresubmitNotifyResult(
1046 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1047 if not input_api.change.issue:
1048 return [output_api.PresubmitError(
1049 "DEPS approval by OWNERS check failed: this change has "
1050 "no Rietveld issue number, so we can't check it for approvals.")]
1051 output = output_api.PresubmitError
1052 else:
1053 output = output_api.PresubmitNotifyResult
1054
1055 owners_db = input_api.owners_db
1056 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1057 input_api,
1058 owners_db.email_regexp,
1059 approval_needed=input_api.is_committing)
1060
1061 owner_email = owner_email or input_api.change.author_email
1062
[email protected]de4f7d22013-05-23 14:27:461063 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511064 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461065 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551066 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1067 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411068
1069 # We strip the /DEPS part that was added by
1070 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1071 # directory.
1072 def StripDeps(path):
1073 start_deps = path.rfind('/DEPS')
1074 if start_deps != -1:
1075 return path[:start_deps]
1076 else:
1077 return path
1078 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551079 for path in missing_files]
1080
1081 if unapproved_dependencies:
1082 output_list = [
[email protected]14a6131c2014-01-08 01:15:411083 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551084 '\n '.join(sorted(unapproved_dependencies)))]
1085 if not input_api.is_committing:
1086 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1087 output_list.append(output(
1088 'Suggested missing target path OWNERS:\n %s' %
1089 '\n '.join(suggested_owners or [])))
1090 return output_list
1091
1092 return []
1093
1094
[email protected]85218562013-11-22 07:41:401095def _CheckSpamLogging(input_api, output_api):
1096 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1097 black_list = (_EXCLUDED_PATHS +
1098 _TEST_CODE_EXCLUDED_PATHS +
1099 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501100 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191101 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481102 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461103 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121104 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1105 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581106 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161107 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031108 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151109 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1110 r"^chromecast[\\\/]",
1111 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311112 r"^components[\\\/]html_viewer[\\\/]"
1113 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461114 # TODO(peter): Remove this exception. https://crbug.com/534537
1115 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1116 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251117 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1118 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111119 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151120 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111121 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521122 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501123 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361124 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311125 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131126 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441127 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451128 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021129 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441130 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401131 source_file_filter = lambda x: input_api.FilterSourceFile(
1132 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1133
1134 log_info = []
1135 printf = []
1136
1137 for f in input_api.AffectedSourceFiles(source_file_filter):
1138 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471139 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401140 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471141 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131142 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371143
mohan.reddyf21db962014-10-16 12:26:471144 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371145 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471146 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401147 printf.append(f.LocalPath())
1148
1149 if log_info:
1150 return [output_api.PresubmitError(
1151 'These files spam the console log with LOG(INFO):',
1152 items=log_info)]
1153 if printf:
1154 return [output_api.PresubmitError(
1155 'These files spam the console log with printf/fprintf:',
1156 items=printf)]
1157 return []
1158
1159
[email protected]49aa76a2013-12-04 06:59:161160def _CheckForAnonymousVariables(input_api, output_api):
1161 """These types are all expected to hold locks while in scope and
1162 so should never be anonymous (which causes them to be immediately
1163 destroyed)."""
1164 they_who_must_be_named = [
1165 'base::AutoLock',
1166 'base::AutoReset',
1167 'base::AutoUnlock',
1168 'SkAutoAlphaRestore',
1169 'SkAutoBitmapShaderInstall',
1170 'SkAutoBlitterChoose',
1171 'SkAutoBounderCommit',
1172 'SkAutoCallProc',
1173 'SkAutoCanvasRestore',
1174 'SkAutoCommentBlock',
1175 'SkAutoDescriptor',
1176 'SkAutoDisableDirectionCheck',
1177 'SkAutoDisableOvalCheck',
1178 'SkAutoFree',
1179 'SkAutoGlyphCache',
1180 'SkAutoHDC',
1181 'SkAutoLockColors',
1182 'SkAutoLockPixels',
1183 'SkAutoMalloc',
1184 'SkAutoMaskFreeImage',
1185 'SkAutoMutexAcquire',
1186 'SkAutoPathBoundsUpdate',
1187 'SkAutoPDFRelease',
1188 'SkAutoRasterClipValidate',
1189 'SkAutoRef',
1190 'SkAutoTime',
1191 'SkAutoTrace',
1192 'SkAutoUnref',
1193 ]
1194 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1195 # bad: base::AutoLock(lock.get());
1196 # not bad: base::AutoLock lock(lock.get());
1197 bad_pattern = input_api.re.compile(anonymous)
1198 # good: new base::AutoLock(lock.get())
1199 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1200 errors = []
1201
1202 for f in input_api.AffectedFiles():
1203 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1204 continue
1205 for linenum, line in f.ChangedContents():
1206 if bad_pattern.search(line) and not good_pattern.search(line):
1207 errors.append('%s:%d' % (f.LocalPath(), linenum))
1208
1209 if errors:
1210 return [output_api.PresubmitError(
1211 'These lines create anonymous variables that need to be named:',
1212 items=errors)]
1213 return []
1214
1215
[email protected]5fe0f8742013-11-29 01:04:591216def _CheckCygwinShell(input_api, output_api):
1217 source_file_filter = lambda x: input_api.FilterSourceFile(
1218 x, white_list=(r'.+\.(gyp|gypi)$',))
1219 cygwin_shell = []
1220
1221 for f in input_api.AffectedSourceFiles(source_file_filter):
1222 for linenum, line in f.ChangedContents():
1223 if 'msvs_cygwin_shell' in line:
1224 cygwin_shell.append(f.LocalPath())
1225 break
1226
1227 if cygwin_shell:
1228 return [output_api.PresubmitError(
1229 'These files should not use msvs_cygwin_shell (the default is 0):',
1230 items=cygwin_shell)]
1231 return []
1232
[email protected]85218562013-11-22 07:41:401233
[email protected]999261d2014-03-03 20:08:081234def _CheckUserActionUpdate(input_api, output_api):
1235 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521236 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081237 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521238 # If actions.xml is already included in the changelist, the PRESUBMIT
1239 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081240 return []
1241
[email protected]999261d2014-03-03 20:08:081242 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1243 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521244 current_actions = None
[email protected]999261d2014-03-03 20:08:081245 for f in input_api.AffectedFiles(file_filter=file_filter):
1246 for line_num, line in f.ChangedContents():
1247 match = input_api.re.search(action_re, line)
1248 if match:
[email protected]2f92dec2014-03-07 19:21:521249 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1250 # loaded only once.
1251 if not current_actions:
1252 with open('tools/metrics/actions/actions.xml') as actions_f:
1253 current_actions = actions_f.read()
1254 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081255 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521256 action = 'name="{0}"'.format(action_name)
1257 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081258 return [output_api.PresubmitPromptWarning(
1259 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521260 'tools/metrics/actions/actions.xml. Please run '
1261 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081262 % (f.LocalPath(), line_num, action_name))]
1263 return []
1264
1265
[email protected]99171a92014-06-03 08:44:471266def _GetJSONParseError(input_api, filename, eat_comments=True):
1267 try:
1268 contents = input_api.ReadFile(filename)
1269 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131270 import sys
1271 original_sys_path = sys.path
1272 try:
1273 sys.path = sys.path + [input_api.os_path.join(
1274 input_api.PresubmitLocalPath(),
1275 'tools', 'json_comment_eater')]
1276 import json_comment_eater
1277 finally:
1278 sys.path = original_sys_path
1279 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471280
1281 input_api.json.loads(contents)
1282 except ValueError as e:
1283 return e
1284 return None
1285
1286
1287def _GetIDLParseError(input_api, filename):
1288 try:
1289 contents = input_api.ReadFile(filename)
1290 idl_schema = input_api.os_path.join(
1291 input_api.PresubmitLocalPath(),
1292 'tools', 'json_schema_compiler', 'idl_schema.py')
1293 process = input_api.subprocess.Popen(
1294 [input_api.python_executable, idl_schema],
1295 stdin=input_api.subprocess.PIPE,
1296 stdout=input_api.subprocess.PIPE,
1297 stderr=input_api.subprocess.PIPE,
1298 universal_newlines=True)
1299 (_, error) = process.communicate(input=contents)
1300 return error or None
1301 except ValueError as e:
1302 return e
1303
1304
1305def _CheckParseErrors(input_api, output_api):
1306 """Check that IDL and JSON files do not contain syntax errors."""
1307 actions = {
1308 '.idl': _GetIDLParseError,
1309 '.json': _GetJSONParseError,
1310 }
1311 # These paths contain test data and other known invalid JSON files.
1312 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491313 r'test[\\\/]data[\\\/]',
1314 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471315 ]
1316 # Most JSON files are preprocessed and support comments, but these do not.
1317 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491318 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471319 ]
1320 # Only run IDL checker on files in these directories.
1321 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491322 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1323 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471324 ]
1325
1326 def get_action(affected_file):
1327 filename = affected_file.LocalPath()
1328 return actions.get(input_api.os_path.splitext(filename)[1])
1329
1330 def MatchesFile(patterns, path):
1331 for pattern in patterns:
1332 if input_api.re.search(pattern, path):
1333 return True
1334 return False
1335
1336 def FilterFile(affected_file):
1337 action = get_action(affected_file)
1338 if not action:
1339 return False
1340 path = affected_file.LocalPath()
1341
1342 if MatchesFile(excluded_patterns, path):
1343 return False
1344
1345 if (action == _GetIDLParseError and
1346 not MatchesFile(idl_included_patterns, path)):
1347 return False
1348 return True
1349
1350 results = []
1351 for affected_file in input_api.AffectedFiles(
1352 file_filter=FilterFile, include_deletes=False):
1353 action = get_action(affected_file)
1354 kwargs = {}
1355 if (action == _GetJSONParseError and
1356 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1357 kwargs['eat_comments'] = False
1358 parse_error = action(input_api,
1359 affected_file.AbsoluteLocalPath(),
1360 **kwargs)
1361 if parse_error:
1362 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1363 (affected_file.LocalPath(), parse_error)))
1364 return results
1365
1366
[email protected]760deea2013-12-10 19:33:491367def _CheckJavaStyle(input_api, output_api):
1368 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471369 import sys
[email protected]760deea2013-12-10 19:33:491370 original_sys_path = sys.path
1371 try:
1372 sys.path = sys.path + [input_api.os_path.join(
1373 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1374 import checkstyle
1375 finally:
1376 # Restore sys.path to what it was before.
1377 sys.path = original_sys_path
1378
1379 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091380 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511381 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491382
1383
dskiba88634f4e2015-08-14 23:03:291384def _CheckAndroidToastUsage(input_api, output_api):
1385 """Checks that code uses org.chromium.ui.widget.Toast instead of
1386 android.widget.Toast (Chromium Toast doesn't force hardware
1387 acceleration on low-end devices, saving memory).
1388 """
1389 toast_import_pattern = input_api.re.compile(
1390 r'^import android\.widget\.Toast;$')
1391
1392 errors = []
1393
1394 sources = lambda affected_file: input_api.FilterSourceFile(
1395 affected_file,
1396 black_list=(_EXCLUDED_PATHS +
1397 _TEST_CODE_EXCLUDED_PATHS +
1398 input_api.DEFAULT_BLACK_LIST +
1399 (r'^chromecast[\\\/].*',
1400 r'^remoting[\\\/].*')),
1401 white_list=(r'.*\.java$',))
1402
1403 for f in input_api.AffectedSourceFiles(sources):
1404 for line_num, line in f.ChangedContents():
1405 if toast_import_pattern.search(line):
1406 errors.append("%s:%d" % (f.LocalPath(), line_num))
1407
1408 results = []
1409
1410 if errors:
1411 results.append(output_api.PresubmitError(
1412 'android.widget.Toast usage is detected. Android toasts use hardware'
1413 ' acceleration, and can be\ncostly on low-end devices. Please use'
1414 ' org.chromium.ui.widget.Toast instead.\n'
1415 'Contact [email protected] if you have any questions.',
1416 errors))
1417
1418 return results
1419
1420
dgnaa68d5e2015-06-10 10:08:221421def _CheckAndroidCrLogUsage(input_api, output_api):
1422 """Checks that new logs using org.chromium.base.Log:
1423 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511424 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221425 """
1426 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121427 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1428 class_in_base_pattern = input_api.re.compile(
1429 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1430 has_some_log_import_pattern = input_api.re.compile(
1431 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221432 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121433 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221434 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511435 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221436 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221437
Vincent Scheib16d7b272015-09-15 18:09:071438 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221439 'or contact [email protected] for more info.')
1440 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121441
dgnaa68d5e2015-06-10 10:08:221442 tag_decl_errors = []
1443 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121444 tag_errors = []
dgn38736db2015-09-18 19:20:511445 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121446 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221447
1448 for f in input_api.AffectedSourceFiles(sources):
1449 file_content = input_api.ReadFile(f)
1450 has_modified_logs = False
1451
1452 # Per line checks
dgn87d9fb62015-06-12 09:15:121453 if (cr_log_import_pattern.search(file_content) or
1454 (class_in_base_pattern.search(file_content) and
1455 not has_some_log_import_pattern.search(file_content))):
1456 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221457 for line_num, line in f.ChangedContents():
1458
1459 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121460 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221461 if match:
1462 has_modified_logs = True
1463
1464 # Make sure it uses "TAG"
1465 if not match.group('tag') == 'TAG':
1466 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121467 else:
1468 # Report non cr Log function calls in changed lines
1469 for line_num, line in f.ChangedContents():
1470 if log_call_pattern.search(line):
1471 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221472
1473 # Per file checks
1474 if has_modified_logs:
1475 # Make sure the tag is using the "cr" prefix and is not too long
1476 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511477 tag_name = match.group('name') if match else None
1478 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221479 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511480 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221481 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511482 elif '.' in tag_name:
1483 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221484
1485 results = []
1486 if tag_decl_errors:
1487 results.append(output_api.PresubmitPromptWarning(
1488 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511489 '"private static final String TAG = "<package tag>".\n'
1490 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221491 tag_decl_errors))
1492
1493 if tag_length_errors:
1494 results.append(output_api.PresubmitError(
1495 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511496 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221497 tag_length_errors))
1498
1499 if tag_errors:
1500 results.append(output_api.PresubmitPromptWarning(
1501 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1502 tag_errors))
1503
dgn87d9fb62015-06-12 09:15:121504 if util_log_errors:
dgn4401aa52015-04-29 16:26:171505 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121506 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1507 util_log_errors))
1508
dgn38736db2015-09-18 19:20:511509 if tag_with_dot_errors:
1510 results.append(output_api.PresubmitPromptWarning(
1511 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1512 tag_with_dot_errors))
1513
dgn4401aa52015-04-29 16:26:171514 return results
1515
1516
agrieve7b6479d82015-10-07 14:24:221517def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1518 """Checks if MDPI assets are placed in a correct directory."""
1519 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1520 ('/res/drawable/' in f.LocalPath() or
1521 '/res/drawable-ldrtl/' in f.LocalPath()))
1522 errors = []
1523 for f in input_api.AffectedFiles(include_deletes=False,
1524 file_filter=file_filter):
1525 errors.append(' %s' % f.LocalPath())
1526
1527 results = []
1528 if errors:
1529 results.append(output_api.PresubmitError(
1530 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1531 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1532 '/res/drawable-ldrtl/.\n'
1533 'Contact [email protected] if you have questions.', errors))
1534 return results
1535
1536
agrievef32bcc72016-04-04 14:57:401537class PydepsChecker(object):
1538 def __init__(self, input_api, pydeps_files):
1539 self._file_cache = {}
1540 self._input_api = input_api
1541 self._pydeps_files = pydeps_files
1542
1543 def _LoadFile(self, path):
1544 """Returns the list of paths within a .pydeps file relative to //."""
1545 if path not in self._file_cache:
1546 with open(path) as f:
1547 self._file_cache[path] = f.read()
1548 return self._file_cache[path]
1549
1550 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1551 """Returns an interable of paths within the .pydep, relativized to //."""
1552 os_path = self._input_api.os_path
1553 pydeps_dir = os_path.dirname(pydeps_path)
1554 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1555 if not l.startswith('*'))
1556 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1557
1558 def _CreateFilesToPydepsMap(self):
1559 """Returns a map of local_path -> list_of_pydeps."""
1560 ret = {}
1561 for pydep_local_path in self._pydeps_files:
1562 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1563 ret.setdefault(path, []).append(pydep_local_path)
1564 return ret
1565
1566 def ComputeAffectedPydeps(self):
1567 """Returns an iterable of .pydeps files that might need regenerating."""
1568 affected_pydeps = set()
1569 file_to_pydeps_map = None
1570 for f in self._input_api.AffectedFiles(include_deletes=True):
1571 local_path = f.LocalPath()
1572 if local_path == 'DEPS':
1573 return self._pydeps_files
1574 elif local_path.endswith('.pydeps'):
1575 if local_path in self._pydeps_files:
1576 affected_pydeps.add(local_path)
1577 elif local_path.endswith('.py'):
1578 if file_to_pydeps_map is None:
1579 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1580 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1581 return affected_pydeps
1582
1583 def DetermineIfStale(self, pydeps_path):
1584 """Runs print_python_deps.py to see if the files is stale."""
1585 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1586 cmd = old_pydeps_data[1][1:].strip()
1587 new_pydeps_data = self._input_api.subprocess.check_output(
1588 cmd + ' --output ""', shell=True)
1589 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
1590 return cmd
1591
1592
1593def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1594 """Checks if a .pydeps file needs to be regenerated."""
1595 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1596 is_android = input_api.os_path.exists('third_party/android_tools')
1597 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1598 results = []
1599 # First, check for new / deleted .pydeps.
1600 for f in input_api.AffectedFiles(include_deletes=True):
1601 if f.LocalPath().endswith('.pydeps'):
1602 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1603 results.append(output_api.PresubmitError(
1604 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1605 'remove %s' % f.LocalPath()))
1606 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1607 results.append(output_api.PresubmitError(
1608 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1609 'include %s' % f.LocalPath()))
1610
1611 if results:
1612 return results
1613
1614 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1615
1616 for pydep_path in checker.ComputeAffectedPydeps():
1617 try:
1618 cmd = checker.DetermineIfStale(pydep_path)
1619 if cmd:
1620 results.append(output_api.PresubmitError(
1621 'File is stale: %s\nTo regenerate, run:\n\n %s' %
1622 (pydep_path, cmd)))
1623 except input_api.subprocess.CalledProcessError as error:
1624 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1625 long_text=error.output)]
1626
1627 return results
1628
1629
mnaganov9b9b1fe82014-12-11 16:30:361630def _CheckForCopyrightedCode(input_api, output_api):
1631 """Verifies that newly added code doesn't contain copyrighted material
1632 and is properly licensed under the standard Chromium license.
1633
1634 As there can be false positives, we maintain a whitelist file. This check
1635 also verifies that the whitelist file is up to date.
1636 """
1637 import sys
1638 original_sys_path = sys.path
1639 try:
1640 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221641 input_api.PresubmitLocalPath(), 'tools')]
1642 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361643 finally:
1644 # Restore sys.path to what it was before.
1645 sys.path = original_sys_path
1646
1647 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1648
1649
glidere61efad2015-02-18 17:39:431650def _CheckSingletonInHeaders(input_api, output_api):
1651 """Checks to make sure no header files have |Singleton<|."""
1652 def FileFilter(affected_file):
1653 # It's ok for base/memory/singleton.h to have |Singleton<|.
1654 black_list = (_EXCLUDED_PATHS +
1655 input_api.DEFAULT_BLACK_LIST +
1656 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1657 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1658
sergeyu34d21222015-09-16 00:11:441659 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431660 files = []
1661 for f in input_api.AffectedSourceFiles(FileFilter):
1662 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1663 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1664 contents = input_api.ReadFile(f)
1665 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241666 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431667 pattern.search(line)):
1668 files.append(f)
1669 break
1670
1671 if files:
yolandyandaabc6d2016-04-18 18:29:391672 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441673 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431674 'Please move them to an appropriate source file so that the ' +
1675 'template gets instantiated in a single compilation unit.',
1676 files) ]
1677 return []
1678
1679
dbeam37e8e7402016-02-10 22:58:201680def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api):
1681 """Checks for old style compiled_resources.gyp files."""
1682 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1683
1684 added_compiled_resources = filter(is_compiled_resource, [
1685 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1686 ])
1687
1688 if not added_compiled_resources:
1689 return []
1690
1691 return [output_api.PresubmitError(
1692 "Found new compiled_resources.gyp files:\n%s\n\n"
1693 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551694 "please use compiled_resources2.gyp instead:\n"
1695 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1696 %
dbeam37e8e7402016-02-10 22:58:201697 "\n".join(added_compiled_resources))]
1698
1699
[email protected]fd20b902014-05-09 02:14:531700_DEPRECATED_CSS = [
1701 # Values
1702 ( "-webkit-box", "flex" ),
1703 ( "-webkit-inline-box", "inline-flex" ),
1704 ( "-webkit-flex", "flex" ),
1705 ( "-webkit-inline-flex", "inline-flex" ),
1706 ( "-webkit-min-content", "min-content" ),
1707 ( "-webkit-max-content", "max-content" ),
1708
1709 # Properties
1710 ( "-webkit-background-clip", "background-clip" ),
1711 ( "-webkit-background-origin", "background-origin" ),
1712 ( "-webkit-background-size", "background-size" ),
1713 ( "-webkit-box-shadow", "box-shadow" ),
1714
1715 # Functions
1716 ( "-webkit-gradient", "gradient" ),
1717 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1718 ( "-webkit-linear-gradient", "linear-gradient" ),
1719 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1720 ( "-webkit-radial-gradient", "radial-gradient" ),
1721 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1722]
1723
1724def _CheckNoDeprecatedCSS(input_api, output_api):
1725 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251726 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341727 documentation and iOS CSS for dom distiller
1728 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251729 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531730 results = []
dbeam070cfe62014-10-22 06:44:021731 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251732 black_list = (_EXCLUDED_PATHS +
1733 _TEST_CODE_EXCLUDED_PATHS +
1734 input_api.DEFAULT_BLACK_LIST +
1735 (r"^chrome/common/extensions/docs",
1736 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341737 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051738 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441739 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251740 r"^native_client_sdk"))
1741 file_filter = lambda f: input_api.FilterSourceFile(
1742 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531743 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1744 for line_num, line in fpath.ChangedContents():
1745 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021746 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531747 results.append(output_api.PresubmitError(
1748 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1749 (fpath.LocalPath(), line_num, deprecated_value, value)))
1750 return results
1751
mohan.reddyf21db962014-10-16 12:26:471752
dbeam070cfe62014-10-22 06:44:021753_DEPRECATED_JS = [
1754 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1755 ( "__defineGetter__", "Object.defineProperty" ),
1756 ( "__defineSetter__", "Object.defineProperty" ),
1757]
1758
1759def _CheckNoDeprecatedJS(input_api, output_api):
1760 """Make sure that we don't use deprecated JS in Chrome code."""
1761 results = []
1762 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1763 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1764 input_api.DEFAULT_BLACK_LIST)
1765 file_filter = lambda f: input_api.FilterSourceFile(
1766 f, white_list=file_inclusion_pattern, black_list=black_list)
1767 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1768 for lnum, line in fpath.ChangedContents():
1769 for (deprecated, replacement) in _DEPRECATED_JS:
1770 if deprecated in line:
1771 results.append(output_api.PresubmitError(
1772 "%s:%d: Use of deprecated JS %s, use %s instead" %
1773 (fpath.LocalPath(), lnum, deprecated, replacement)))
1774 return results
1775
1776
dgnaa68d5e2015-06-10 10:08:221777def _AndroidSpecificOnUploadChecks(input_api, output_api):
1778 """Groups checks that target android code."""
1779 results = []
dgnaa68d5e2015-06-10 10:08:221780 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221781 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291782 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221783 return results
1784
1785
[email protected]22c9bd72011-03-27 16:47:391786def _CommonChecks(input_api, output_api):
1787 """Checks common to both upload and commit."""
1788 results = []
1789 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381790 input_api, output_api,
1791 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461792 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191793 results.extend(
[email protected]760deea2013-12-10 19:33:491794 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541795 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181796 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521797 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221798 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441799 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591800 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061801 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121802 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181803 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221804 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491805 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271806 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031807 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491808 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441809 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271810 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541811 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441812 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:391813 results.extend(_CheckFlakyTestUsage(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461814 # TODO(danakj): Remove this when base/move.h is removed.
dchengcf95c122015-12-18 08:29:161815 results.extend(_CheckForUsingPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551816 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041817 results.extend(
1818 input_api.canned_checks.CheckChangeHasNoTabs(
1819 input_api,
1820 output_api,
1821 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401822 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161823 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591824 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081825 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531826 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021827 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471828 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041829 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361830 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231831 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431832 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam37e8e7402016-02-10 22:58:201833 results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
agrievef32bcc72016-04-04 14:57:401834 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241835
1836 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1837 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1838 input_api, output_api,
1839 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381840 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391841 return results
[email protected]1f7b4172010-01-28 01:17:341842
[email protected]b337cb5b2011-01-23 21:24:051843
[email protected]66daa702011-05-28 14:41:461844def _CheckAuthorizedAuthor(input_api, output_api):
1845 """For non-googler/chromites committers, verify the author's email address is
1846 in AUTHORS.
1847 """
[email protected]9bb9cb82011-06-13 20:43:011848 # TODO(maruel): Add it to input_api?
1849 import fnmatch
1850
[email protected]66daa702011-05-28 14:41:461851 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011852 if not author:
1853 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461854 return []
[email protected]c99663292011-05-31 19:46:081855 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461856 input_api.PresubmitLocalPath(), 'AUTHORS')
1857 valid_authors = (
1858 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1859 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181860 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441861 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231862 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461863 return [output_api.PresubmitPromptWarning(
1864 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1865 '\n'
1866 'http://www.chromium.org/developers/contributing-code and read the '
1867 '"Legal" section\n'
1868 'If you are a chromite, verify the contributor signed the CLA.') %
1869 author)]
1870 return []
1871
1872
[email protected]b8079ae4a2012-12-05 19:56:491873def _CheckPatchFiles(input_api, output_api):
1874 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1875 if f.LocalPath().endswith(('.orig', '.rej'))]
1876 if problems:
1877 return [output_api.PresubmitError(
1878 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031879 else:
1880 return []
[email protected]b8079ae4a2012-12-05 19:56:491881
1882
[email protected]b00342e7f2013-03-26 16:21:541883def _DidYouMeanOSMacro(bad_macro):
1884 try:
1885 return {'A': 'OS_ANDROID',
1886 'B': 'OS_BSD',
1887 'C': 'OS_CHROMEOS',
1888 'F': 'OS_FREEBSD',
1889 'L': 'OS_LINUX',
1890 'M': 'OS_MACOSX',
1891 'N': 'OS_NACL',
1892 'O': 'OS_OPENBSD',
1893 'P': 'OS_POSIX',
1894 'S': 'OS_SOLARIS',
1895 'W': 'OS_WIN'}[bad_macro[3].upper()]
1896 except KeyError:
1897 return ''
1898
1899
1900def _CheckForInvalidOSMacrosInFile(input_api, f):
1901 """Check for sensible looking, totally invalid OS macros."""
1902 preprocessor_statement = input_api.re.compile(r'^\s*#')
1903 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1904 results = []
1905 for lnum, line in f.ChangedContents():
1906 if preprocessor_statement.search(line):
1907 for match in os_macro.finditer(line):
1908 if not match.group(1) in _VALID_OS_MACROS:
1909 good = _DidYouMeanOSMacro(match.group(1))
1910 did_you_mean = ' (did you mean %s?)' % good if good else ''
1911 results.append(' %s:%d %s%s' % (f.LocalPath(),
1912 lnum,
1913 match.group(1),
1914 did_you_mean))
1915 return results
1916
1917
1918def _CheckForInvalidOSMacros(input_api, output_api):
1919 """Check all affected files for invalid OS macros."""
1920 bad_macros = []
1921 for f in input_api.AffectedFiles():
1922 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1923 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1924
1925 if not bad_macros:
1926 return []
1927
1928 return [output_api.PresubmitError(
1929 'Possibly invalid OS macro[s] found. Please fix your code\n'
1930 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1931
lliabraa35bab3932014-10-01 12:16:441932
1933def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1934 """Check all affected files for invalid "if defined" macros."""
1935 ALWAYS_DEFINED_MACROS = (
1936 "TARGET_CPU_PPC",
1937 "TARGET_CPU_PPC64",
1938 "TARGET_CPU_68K",
1939 "TARGET_CPU_X86",
1940 "TARGET_CPU_ARM",
1941 "TARGET_CPU_MIPS",
1942 "TARGET_CPU_SPARC",
1943 "TARGET_CPU_ALPHA",
1944 "TARGET_IPHONE_SIMULATOR",
1945 "TARGET_OS_EMBEDDED",
1946 "TARGET_OS_IPHONE",
1947 "TARGET_OS_MAC",
1948 "TARGET_OS_UNIX",
1949 "TARGET_OS_WIN32",
1950 )
1951 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1952 results = []
1953 for lnum, line in f.ChangedContents():
1954 for match in ifdef_macro.finditer(line):
1955 if match.group(1) in ALWAYS_DEFINED_MACROS:
1956 always_defined = ' %s is always defined. ' % match.group(1)
1957 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1958 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1959 lnum,
1960 always_defined,
1961 did_you_mean))
1962 return results
1963
1964
1965def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1966 """Check all affected files for invalid "if defined" macros."""
1967 bad_macros = []
1968 for f in input_api.AffectedFiles():
1969 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1970 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1971
1972 if not bad_macros:
1973 return []
1974
1975 return [output_api.PresubmitError(
1976 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1977 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1978 bad_macros)]
1979
1980
dchengcf95c122015-12-18 08:29:161981def _CheckForUsingPass(input_api, output_api):
danakj3c84d0c2014-10-06 15:35:461982 """Check all affected files for using side effects of Pass."""
1983 errors = []
1984 for f in input_api.AffectedFiles():
1985 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1986 for lnum, line in f.ChangedContents():
dchengcf95c122015-12-18 08:29:161987 # Warn on any use of foo.Pass().
1988 if input_api.re.search(r'[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461989 errors.append(output_api.PresubmitError(
dchengcf95c122015-12-18 08:29:161990 ('%s:%d uses Pass(); please use std::move() instead. ' +
1991 'See crbug.com/557422.') % (f.LocalPath(), lnum)))
danakj3c84d0c2014-10-06 15:35:461992 return errors
1993
1994
mlamouria82272622014-09-16 18:45:041995def _CheckForIPCRules(input_api, output_api):
1996 """Check for same IPC rules described in
1997 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1998 """
1999 base_pattern = r'IPC_ENUM_TRAITS\('
2000 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2001 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2002
2003 problems = []
2004 for f in input_api.AffectedSourceFiles(None):
2005 local_path = f.LocalPath()
2006 if not local_path.endswith('.h'):
2007 continue
2008 for line_number, line in f.ChangedContents():
2009 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2010 problems.append(
2011 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2012
2013 if problems:
2014 return [output_api.PresubmitPromptWarning(
2015 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2016 else:
2017 return []
2018
[email protected]b00342e7f2013-03-26 16:21:542019
mostynbb639aca52015-01-07 20:31:232020def _CheckForWindowsLineEndings(input_api, output_api):
2021 """Check source code and known ascii text files for Windows style line
2022 endings.
2023 """
earthdok1b5e0ee2015-03-10 15:19:102024 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232025
2026 file_inclusion_pattern = (
2027 known_text_files,
2028 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2029 )
2030
2031 filter = lambda f: input_api.FilterSourceFile(
2032 f, white_list=file_inclusion_pattern, black_list=None)
2033 files = [f.LocalPath() for f in
2034 input_api.AffectedSourceFiles(filter)]
2035
2036 problems = []
2037
2038 for file in files:
2039 fp = open(file, 'r')
2040 for line in fp:
2041 if line.endswith('\r\n'):
2042 problems.append(file)
2043 break
2044 fp.close()
2045
2046 if problems:
2047 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2048 'these files to contain Windows style line endings?\n' +
2049 '\n'.join(problems))]
2050
2051 return []
2052
2053
[email protected]1f7b4172010-01-28 01:17:342054def CheckChangeOnUpload(input_api, output_api):
2055 results = []
2056 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472057 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:172058 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:282059 results.extend(
2060 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192061 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222062 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542063 return results
[email protected]ca8d19842009-02-19 16:33:122064
2065
[email protected]1bfb8322014-04-23 01:02:412066def GetTryServerMasterForBot(bot):
2067 """Returns the Try Server master for the given bot.
2068
[email protected]0bb112362014-07-26 04:38:322069 It tries to guess the master from the bot name, but may still fail
2070 and return None. There is no longer a default master.
2071 """
2072 # Potentially ambiguous bot names are listed explicitly.
2073 master_map = {
[email protected]0bb112362014-07-26 04:38:322074 'chromium_presubmit': 'tryserver.chromium.linux',
[email protected]0bb112362014-07-26 04:38:322075 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412076 }
[email protected]0bb112362014-07-26 04:38:322077 master = master_map.get(bot)
2078 if not master:
sergiyb37fd293f2015-02-26 06:55:012079 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:322080 master = 'tryserver.chromium.linux'
2081 elif 'win' in bot:
2082 master = 'tryserver.chromium.win'
2083 elif 'mac' in bot or 'ios' in bot:
2084 master = 'tryserver.chromium.mac'
2085 return master
[email protected]1bfb8322014-04-23 01:02:412086
2087
Paweł Hajdan, Jr55083782014-12-19 20:32:562088def GetDefaultTryConfigs(bots):
2089 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012090 """
2091
Paweł Hajdan, Jr55083782014-12-19 20:32:562092 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412093
2094 # Build up the mapping from tryserver master to bot/test.
2095 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562096 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412097 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2098 return out
[email protected]38c6a512013-12-18 23:48:012099
2100
[email protected]ca8d19842009-02-19 16:33:122101def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542102 results = []
[email protected]1f7b4172010-01-28 01:17:342103 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542104 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272105 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342106 input_api,
2107 output_api,
[email protected]2fdd1f362013-01-16 03:56:032108 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272109
[email protected]3e4eb112011-01-18 03:29:542110 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2111 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412112 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2113 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542114 return results