blob: df38b007146b6f30ea723bbe1e02a13ecd334abd [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 '
brucedawson70fadb02015-06-30 17:47:5567 'collation (LC_COLLATE=C) and check\nhttps://google-styleguide.googlecode'
marjaa017dc482015-03-09 17:13:4068 '.com/svn/trunk/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 (
thestig75844fdb2014-09-09 19:47:10167 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22168 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
alematee4016bb2014-11-12 17:38:51169 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
170 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09171 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
[email protected]de7d61ff2013-08-20 11:30:41172 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
173 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48174 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
175 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01176 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54177 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu34d21222015-09-16 00:11:44178 r"^remoting[\\\/]host[\\\/]gnubby_auth_handler_posix\.cc$",
dnicoara171d8c82015-03-05 20:46:18179 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
dnicoarab29d0512015-05-07 19:29:23180 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49181 ),
[email protected]23e6cbc2012-06-16 18:51:20182 ),
[email protected]52657f62013-05-20 05:30:31183 (
184 'SkRefPtr',
185 (
186 'The use of SkRefPtr is prohibited. ',
187 'Please use skia::RefPtr instead.'
188 ),
189 True,
190 (),
191 ),
192 (
193 'SkAutoRef',
194 (
195 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
196 'Please use skia::RefPtr instead.'
197 ),
198 True,
199 (),
200 ),
201 (
202 'SkAutoTUnref',
203 (
204 'The use of SkAutoTUnref is dangerous because it implicitly ',
205 'converts to a raw pointer. Please use skia::RefPtr instead.'
206 ),
207 True,
208 (),
209 ),
210 (
211 'SkAutoUnref',
212 (
213 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
214 'because it implicitly converts to a raw pointer. ',
215 'Please use skia::RefPtr instead.'
216 ),
217 True,
218 (),
219 ),
[email protected]d89eec82013-12-03 14:10:59220 (
221 r'/HANDLE_EINTR\(.*close',
222 (
223 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
224 'descriptor will be closed, and it is incorrect to retry the close.',
225 'Either call close directly and ignore its return value, or wrap close',
226 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
227 ),
228 True,
229 (),
230 ),
231 (
232 r'/IGNORE_EINTR\((?!.*close)',
233 (
234 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
235 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
236 ),
237 True,
238 (
239 # Files that #define IGNORE_EINTR.
240 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
241 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
242 ),
243 ),
[email protected]ec5b3f02014-04-04 18:43:43244 (
245 r'/v8::Extension\(',
246 (
247 'Do not introduce new v8::Extensions into the code base, use',
248 'gin::Wrappable instead. See http://crbug.com/334679',
249 ),
250 True,
[email protected]f55c90ee62014-04-12 00:50:03251 (
joaodasilva718f87672014-08-30 09:25:49252 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03253 ),
[email protected]ec5b3f02014-04-04 18:43:43254 ),
skyostilf9469f72015-04-20 10:38:52255 (
sdefresneeaeccc52015-04-22 08:18:32256 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52257 (
258 'MessageLoopProxy is deprecated. ',
259 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
260 ),
261 True,
kinuko59024ce2015-04-21 22:18:30262 (
263 # Internal message_loop related code may still use it.
264 r'^base[\\\/]message_loop[\\\/].*',
265 ),
skyostilf9469f72015-04-20 10:38:52266 ),
[email protected]127f18ec2012-06-16 05:05:59267)
268
mlamouria82272622014-09-16 18:45:04269_IPC_ENUM_TRAITS_DEPRECATED = (
270 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
271 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
272
[email protected]127f18ec2012-06-16 05:05:59273
[email protected]b00342e7f2013-03-26 16:21:54274_VALID_OS_MACROS = (
275 # Please keep sorted.
276 'OS_ANDROID',
[email protected]f4440b42014-03-19 05:47:01277 'OS_ANDROID_HOST',
[email protected]b00342e7f2013-03-26 16:21:54278 'OS_BSD',
279 'OS_CAT', # For testing.
280 'OS_CHROMEOS',
281 'OS_FREEBSD',
282 'OS_IOS',
283 'OS_LINUX',
284 'OS_MACOSX',
285 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21286 'OS_NACL_NONSFI',
287 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54288 'OS_OPENBSD',
289 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37290 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54291 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54292 'OS_WIN',
293)
294
295
[email protected]55459852011-08-10 15:17:19296def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
297 """Attempts to prevent use of functions intended only for testing in
298 non-testing code. For now this is just a best-effort implementation
299 that ignores header files and may have some false positives. A
300 better implementation would probably need a proper C++ parser.
301 """
302 # We only scan .cc files and the like, as the declaration of
303 # for-testing functions in header files are hard to distinguish from
304 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44305 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19306
jochenc0d4808c2015-07-27 09:25:42307 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19308 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09309 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19310 exclusion_pattern = input_api.re.compile(
311 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
312 base_function_pattern, base_function_pattern))
313
314 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44315 black_list = (_EXCLUDED_PATHS +
316 _TEST_CODE_EXCLUDED_PATHS +
317 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19318 return input_api.FilterSourceFile(
319 affected_file,
320 white_list=(file_inclusion_pattern, ),
321 black_list=black_list)
322
323 problems = []
324 for f in input_api.AffectedSourceFiles(FilterFile):
325 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24326 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03327 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46328 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03329 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19330 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03331 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19332
333 if problems:
[email protected]f7051d52013-04-02 18:31:42334 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03335 else:
336 return []
[email protected]55459852011-08-10 15:17:19337
338
[email protected]10689ca2011-09-02 02:31:54339def _CheckNoIOStreamInHeaders(input_api, output_api):
340 """Checks to make sure no .h files include <iostream>."""
341 files = []
342 pattern = input_api.re.compile(r'^#include\s*<iostream>',
343 input_api.re.MULTILINE)
344 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
345 if not f.LocalPath().endswith('.h'):
346 continue
347 contents = input_api.ReadFile(f)
348 if pattern.search(contents):
349 files.append(f)
350
351 if len(files):
352 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06353 'Do not #include <iostream> in header files, since it inserts static '
354 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54355 '#include <ostream>. See http://crbug.com/94794',
356 files) ]
357 return []
358
359
[email protected]72df4e782012-06-21 16:28:18360def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
361 """Checks to make sure no source files use UNIT_TEST"""
362 problems = []
363 for f in input_api.AffectedFiles():
364 if (not f.LocalPath().endswith(('.cc', '.mm'))):
365 continue
366
367 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04368 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18369 problems.append(' %s:%d' % (f.LocalPath(), line_num))
370
371 if not problems:
372 return []
373 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
374 '\n'.join(problems))]
375
376
mcasasb7440c282015-02-04 14:52:19377def _FindHistogramNameInLine(histogram_name, line):
378 """Tries to find a histogram name or prefix in a line."""
379 if not "affected-histogram" in line:
380 return histogram_name in line
381 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
382 # the histogram_name.
383 if not '"' in line:
384 return False
385 histogram_prefix = line.split('\"')[1]
386 return histogram_prefix in histogram_name
387
388
389def _CheckUmaHistogramChanges(input_api, output_api):
390 """Check that UMA histogram names in touched lines can still be found in other
391 lines of the patch or in histograms.xml. Note that this check would not catch
392 the reverse: changes in histograms.xml not matched in the code itself."""
393 touched_histograms = []
394 histograms_xml_modifications = []
395 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
396 for f in input_api.AffectedFiles():
397 # If histograms.xml itself is modified, keep the modified lines for later.
398 if f.LocalPath().endswith(('histograms.xml')):
399 histograms_xml_modifications = f.ChangedContents()
400 continue
401 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
402 continue
403 for line_num, line in f.ChangedContents():
404 found = pattern.search(line)
405 if found:
406 touched_histograms.append([found.group(1), f, line_num])
407
408 # Search for the touched histogram names in the local modifications to
409 # histograms.xml, and, if not found, on the base histograms.xml file.
410 unmatched_histograms = []
411 for histogram_info in touched_histograms:
412 histogram_name_found = False
413 for line_num, line in histograms_xml_modifications:
414 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
415 if histogram_name_found:
416 break
417 if not histogram_name_found:
418 unmatched_histograms.append(histogram_info)
419
eromanb90c82e7e32015-04-01 15:13:49420 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19421 problems = []
422 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49423 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19424 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45425 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19426 histogram_name_found = False
427 for line in histograms_xml:
428 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
429 if histogram_name_found:
430 break
431 if not histogram_name_found:
432 problems.append(' [%s:%d] %s' %
433 (f.LocalPath(), line_num, histogram_name))
434
435 if not problems:
436 return []
437 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
438 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49439 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19440
441
[email protected]8ea5d4b2011-09-13 21:49:22442def _CheckNoNewWStrings(input_api, output_api):
443 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27444 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22445 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20446 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57447 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
448 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20449 continue
[email protected]8ea5d4b2011-09-13 21:49:22450
[email protected]a11dbe9b2012-08-07 01:32:58451 allowWString = False
[email protected]b5c24292011-11-28 14:38:20452 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58453 if 'presubmit: allow wstring' in line:
454 allowWString = True
455 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27456 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58457 allowWString = False
458 else:
459 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22460
[email protected]55463aa62011-10-12 00:48:27461 if not problems:
462 return []
463 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58464 ' If you are calling a cross-platform API that accepts a wstring, '
465 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27466 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22467
468
[email protected]2a8ac9c2011-10-19 17:20:44469def _CheckNoDEPSGIT(input_api, output_api):
470 """Make sure .DEPS.git is never modified manually."""
471 if any(f.LocalPath().endswith('.DEPS.git') for f in
472 input_api.AffectedFiles()):
473 return [output_api.PresubmitError(
474 'Never commit changes to .DEPS.git. This file is maintained by an\n'
475 'automated system based on what\'s in DEPS and your changes will be\n'
476 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34477 '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:44478 'for more information')]
479 return []
480
481
tandriief664692014-09-23 14:51:47482def _CheckValidHostsInDEPS(input_api, output_api):
483 """Checks that DEPS file deps are from allowed_hosts."""
484 # Run only if DEPS file has been modified to annoy fewer bystanders.
485 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
486 return []
487 # Outsource work to gclient verify
488 try:
489 input_api.subprocess.check_output(['gclient', 'verify'])
490 return []
491 except input_api.subprocess.CalledProcessError, error:
492 return [output_api.PresubmitError(
493 'DEPS file must have only git dependencies.',
494 long_text=error.output)]
495
496
[email protected]127f18ec2012-06-16 05:05:59497def _CheckNoBannedFunctions(input_api, output_api):
498 """Make sure that banned functions are not used."""
499 warnings = []
500 errors = []
501
502 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
503 for f in input_api.AffectedFiles(file_filter=file_filter):
504 for line_num, line in f.ChangedContents():
505 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26506 matched = False
507 if func_name[0:1] == '/':
508 regex = func_name[1:]
509 if input_api.re.search(regex, line):
510 matched = True
511 elif func_name in line:
512 matched = True
513 if matched:
[email protected]127f18ec2012-06-16 05:05:59514 problems = warnings;
515 if error:
516 problems = errors;
517 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
518 for message_line in message:
519 problems.append(' %s' % message_line)
520
521 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
522 for f in input_api.AffectedFiles(file_filter=file_filter):
523 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49524 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
525 def IsBlacklisted(affected_file, blacklist):
526 local_path = affected_file.LocalPath()
527 for item in blacklist:
528 if input_api.re.match(item, local_path):
529 return True
530 return False
531 if IsBlacklisted(f, excluded_paths):
532 continue
[email protected]d89eec82013-12-03 14:10:59533 matched = False
534 if func_name[0:1] == '/':
535 regex = func_name[1:]
536 if input_api.re.search(regex, line):
537 matched = True
538 elif func_name in line:
539 matched = True
540 if matched:
[email protected]127f18ec2012-06-16 05:05:59541 problems = warnings;
542 if error:
543 problems = errors;
544 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
545 for message_line in message:
546 problems.append(' %s' % message_line)
547
548 result = []
549 if (warnings):
550 result.append(output_api.PresubmitPromptWarning(
551 'Banned functions were used.\n' + '\n'.join(warnings)))
552 if (errors):
553 result.append(output_api.PresubmitError(
554 'Banned functions were used.\n' + '\n'.join(errors)))
555 return result
556
557
[email protected]6c063c62012-07-11 19:11:06558def _CheckNoPragmaOnce(input_api, output_api):
559 """Make sure that banned functions are not used."""
560 files = []
561 pattern = input_api.re.compile(r'^#pragma\s+once',
562 input_api.re.MULTILINE)
563 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
564 if not f.LocalPath().endswith('.h'):
565 continue
566 contents = input_api.ReadFile(f)
567 if pattern.search(contents):
568 files.append(f)
569
570 if files:
571 return [output_api.PresubmitError(
572 'Do not use #pragma once in header files.\n'
573 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
574 files)]
575 return []
576
[email protected]127f18ec2012-06-16 05:05:59577
[email protected]e7479052012-09-19 00:26:12578def _CheckNoTrinaryTrueFalse(input_api, output_api):
579 """Checks to make sure we don't introduce use of foo ? true : false."""
580 problems = []
581 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
582 for f in input_api.AffectedFiles():
583 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
584 continue
585
586 for line_num, line in f.ChangedContents():
587 if pattern.match(line):
588 problems.append(' %s:%d' % (f.LocalPath(), line_num))
589
590 if not problems:
591 return []
592 return [output_api.PresubmitPromptWarning(
593 'Please consider avoiding the "? true : false" pattern if possible.\n' +
594 '\n'.join(problems))]
595
596
[email protected]55f9f382012-07-31 11:02:18597def _CheckUnwantedDependencies(input_api, output_api):
598 """Runs checkdeps on #include statements added in this
599 change. Breaking - rules is an error, breaking ! rules is a
600 warning.
601 """
mohan.reddyf21db962014-10-16 12:26:47602 import sys
[email protected]55f9f382012-07-31 11:02:18603 # We need to wait until we have an input_api object and use this
604 # roundabout construct to import checkdeps because this file is
605 # eval-ed and thus doesn't have __file__.
606 original_sys_path = sys.path
607 try:
608 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47609 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18610 import checkdeps
611 from cpp_checker import CppChecker
612 from rules import Rule
613 finally:
614 # Restore sys.path to what it was before.
615 sys.path = original_sys_path
616
617 added_includes = []
618 for f in input_api.AffectedFiles():
619 if not CppChecker.IsCppFile(f.LocalPath()):
620 continue
621
622 changed_lines = [line for line_num, line in f.ChangedContents()]
623 added_includes.append([f.LocalPath(), changed_lines])
624
[email protected]26385172013-05-09 23:11:35625 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18626
627 error_descriptions = []
628 warning_descriptions = []
629 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
630 added_includes):
631 description_with_path = '%s\n %s' % (path, rule_description)
632 if rule_type == Rule.DISALLOW:
633 error_descriptions.append(description_with_path)
634 else:
635 warning_descriptions.append(description_with_path)
636
637 results = []
638 if error_descriptions:
639 results.append(output_api.PresubmitError(
640 'You added one or more #includes that violate checkdeps rules.',
641 error_descriptions))
642 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42643 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18644 'You added one or more #includes of files that are temporarily\n'
645 'allowed but being removed. Can you avoid introducing the\n'
646 '#include? See relevant DEPS file(s) for details and contacts.',
647 warning_descriptions))
648 return results
649
650
[email protected]fbcafe5a2012-08-08 15:31:22651def _CheckFilePermissions(input_api, output_api):
652 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15653 if input_api.platform == 'win32':
654 return []
mohan.reddyf21db962014-10-16 12:26:47655 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
656 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22657 for f in input_api.AffectedFiles():
658 args += ['--file', f.LocalPath()]
[email protected]f0d330f2014-01-30 01:44:34659 checkperms = input_api.subprocess.Popen(args,
660 stdout=input_api.subprocess.PIPE)
661 errors = checkperms.communicate()[0].strip()
[email protected]fbcafe5a2012-08-08 15:31:22662 if errors:
[email protected]f0d330f2014-01-30 01:44:34663 return [output_api.PresubmitError('checkperms.py failed.',
664 errors.splitlines())]
665 return []
[email protected]fbcafe5a2012-08-08 15:31:22666
667
[email protected]c8278b32012-10-30 20:35:49668def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
669 """Makes sure we don't include ui/aura/window_property.h
670 in header files.
671 """
672 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
673 errors = []
674 for f in input_api.AffectedFiles():
675 if not f.LocalPath().endswith('.h'):
676 continue
677 for line_num, line in f.ChangedContents():
678 if pattern.match(line):
679 errors.append(' %s:%d' % (f.LocalPath(), line_num))
680
681 results = []
682 if errors:
683 results.append(output_api.PresubmitError(
684 'Header files should not include ui/aura/window_property.h', errors))
685 return results
686
687
[email protected]cf9b78f2012-11-14 11:40:28688def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
689 """Checks that the lines in scope occur in the right order.
690
691 1. C system files in alphabetical order
692 2. C++ system files in alphabetical order
693 3. Project's .h files
694 """
695
696 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
697 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
698 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
699
700 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
701
702 state = C_SYSTEM_INCLUDES
703
704 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57705 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28706 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55707 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28708 for line_num, line in scope:
709 if c_system_include_pattern.match(line):
710 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55711 problem_linenums.append((line_num, previous_line_num,
712 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28713 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55714 problem_linenums.append((line_num, previous_line_num,
715 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28716 elif cpp_system_include_pattern.match(line):
717 if state == C_SYSTEM_INCLUDES:
718 state = CPP_SYSTEM_INCLUDES
719 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55720 problem_linenums.append((line_num, previous_line_num,
721 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28722 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55723 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28724 elif custom_include_pattern.match(line):
725 if state != CUSTOM_INCLUDES:
726 state = CUSTOM_INCLUDES
727 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55728 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28729 else:
brucedawson70fadb02015-06-30 17:47:55730 problem_linenums.append((line_num, previous_line_num,
731 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28732 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57733 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28734
735 warnings = []
brucedawson70fadb02015-06-30 17:47:55736 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57737 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55738 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28739 return warnings
740
741
[email protected]ac294a12012-12-06 16:38:43742def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28743 """Checks the #include order for the given file f."""
744
[email protected]2299dcf2012-11-15 19:56:24745 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30746 # Exclude the following includes from the check:
747 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
748 # specific order.
749 # 2) <atlbase.h>, "build/build_config.h"
750 excluded_include_pattern = input_api.re.compile(
751 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24752 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33753 # Match the final or penultimate token if it is xxxtest so we can ignore it
754 # when considering the special first include.
755 test_file_tag_pattern = input_api.re.compile(
756 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11757 if_pattern = input_api.re.compile(
758 r'\s*#\s*(if|elif|else|endif|define|undef).*')
759 # Some files need specialized order of includes; exclude such files from this
760 # check.
761 uncheckable_includes_pattern = input_api.re.compile(
762 r'\s*#include '
763 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28764
765 contents = f.NewContents()
766 warnings = []
767 line_num = 0
768
[email protected]ac294a12012-12-06 16:38:43769 # Handle the special first include. If the first include file is
770 # some/path/file.h, the corresponding including file can be some/path/file.cc,
771 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
772 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33773 # If the included file is some/path/file_platform.h the including file could
774 # also be some/path/file_xxxtest_platform.h.
775 including_file_base_name = test_file_tag_pattern.sub(
776 '', input_api.os_path.basename(f.LocalPath()))
777
[email protected]ac294a12012-12-06 16:38:43778 for line in contents:
779 line_num += 1
780 if system_include_pattern.match(line):
781 # No special first include -> process the line again along with normal
782 # includes.
783 line_num -= 1
784 break
785 match = custom_include_pattern.match(line)
786 if match:
787 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33788 header_basename = test_file_tag_pattern.sub(
789 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
790
791 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24792 # No special first include -> process the line again along with normal
793 # includes.
794 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43795 break
[email protected]cf9b78f2012-11-14 11:40:28796
797 # Split into scopes: Each region between #if and #endif is its own scope.
798 scopes = []
799 current_scope = []
800 for line in contents[line_num:]:
801 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11802 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54803 continue
[email protected]2309b0fa02012-11-16 12:18:27804 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28805 scopes.append(current_scope)
806 current_scope = []
[email protected]962f117e2012-11-22 18:11:56807 elif ((system_include_pattern.match(line) or
808 custom_include_pattern.match(line)) and
809 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28810 current_scope.append((line_num, line))
811 scopes.append(current_scope)
812
813 for scope in scopes:
814 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
815 changed_linenums))
816 return warnings
817
818
819def _CheckIncludeOrder(input_api, output_api):
820 """Checks that the #include order is correct.
821
822 1. The corresponding header for source files.
823 2. C system files in alphabetical order
824 3. C++ system files in alphabetical order
825 4. Project's .h files in alphabetical order
826
[email protected]ac294a12012-12-06 16:38:43827 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
828 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28829 """
[email protected]e120b012014-08-15 19:08:35830 def FileFilterIncludeOrder(affected_file):
831 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
832 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28833
834 warnings = []
[email protected]e120b012014-08-15 19:08:35835 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08836 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43837 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
838 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28839
840 results = []
841 if warnings:
[email protected]f7051d52013-04-02 18:31:42842 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53843 warnings))
[email protected]cf9b78f2012-11-14 11:40:28844 return results
845
846
[email protected]70ca77752012-11-20 03:45:03847def _CheckForVersionControlConflictsInFile(input_api, f):
848 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
849 errors = []
850 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23851 if f.LocalPath().endswith('.md'):
852 # First-level headers in markdown look a lot like version control
853 # conflict markers. http://daringfireball.net/projects/markdown/basics
854 continue
[email protected]70ca77752012-11-20 03:45:03855 if pattern.match(line):
856 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
857 return errors
858
859
860def _CheckForVersionControlConflicts(input_api, output_api):
861 """Usually this is not intentional and will cause a compile failure."""
862 errors = []
863 for f in input_api.AffectedFiles():
864 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
865
866 results = []
867 if errors:
868 results.append(output_api.PresubmitError(
869 'Version control conflict markers found, please resolve.', errors))
870 return results
871
872
[email protected]06e6d0ff2012-12-11 01:36:44873def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
874 def FilterFile(affected_file):
875 """Filter function for use with input_api.AffectedSourceFiles,
876 below. This filters out everything except non-test files from
877 top-level directories that generally speaking should not hard-code
878 service URLs (e.g. src/android_webview/, src/content/ and others).
879 """
880 return input_api.FilterSourceFile(
881 affected_file,
[email protected]78bb39d62012-12-11 15:11:56882 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44883 black_list=(_EXCLUDED_PATHS +
884 _TEST_CODE_EXCLUDED_PATHS +
885 input_api.DEFAULT_BLACK_LIST))
886
[email protected]de4f7d22013-05-23 14:27:46887 base_pattern = '"[^"]*google\.com[^"]*"'
888 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
889 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44890 problems = [] # items are (filename, line_number, line)
891 for f in input_api.AffectedSourceFiles(FilterFile):
892 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46893 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44894 problems.append((f.LocalPath(), line_num, line))
895
896 if problems:
[email protected]f7051d52013-04-02 18:31:42897 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44898 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58899 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44900 [' %s:%d: %s' % (
901 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03902 else:
903 return []
[email protected]06e6d0ff2012-12-11 01:36:44904
905
[email protected]d2530012013-01-25 16:39:27906def _CheckNoAbbreviationInPngFileName(input_api, output_api):
907 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31908 The native_client_sdk directory is excluded because it has auto-generated PNG
909 files for documentation.
[email protected]d2530012013-01-25 16:39:27910 """
[email protected]d2530012013-01-25 16:39:27911 errors = []
binji0dcdf342014-12-12 18:32:31912 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
913 black_list = (r'^native_client_sdk[\\\/]',)
914 file_filter = lambda f: input_api.FilterSourceFile(
915 f, white_list=white_list, black_list=black_list)
916 for f in input_api.AffectedFiles(include_deletes=False,
917 file_filter=file_filter):
918 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27919
920 results = []
921 if errors:
922 results.append(output_api.PresubmitError(
923 'The name of PNG files should not have abbreviations. \n'
924 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
925 'Contact [email protected] if you have questions.', errors))
926 return results
927
928
[email protected]14a6131c2014-01-08 01:15:41929def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08930 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41931 a set of DEPS entries that we should look up.
932
933 For a directory (rather than a specific filename) we fake a path to
934 a specific filename by adding /DEPS. This is chosen as a file that
935 will seldom or never be subject to per-file include_rules.
936 """
[email protected]2b438d62013-11-14 17:54:14937 # We ignore deps entries on auto-generated directories.
938 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08939
940 # This pattern grabs the path without basename in the first
941 # parentheses, and the basename (if present) in the second. It
942 # relies on the simple heuristic that if there is a basename it will
943 # be a header file ending in ".h".
944 pattern = re.compile(
945 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14946 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08947 for changed_line in changed_lines:
948 m = pattern.match(changed_line)
949 if m:
950 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14951 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41952 if m.group(2):
953 results.add('%s%s' % (path, m.group(2)))
954 else:
955 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08956 return results
957
958
[email protected]e871964c2013-05-13 14:14:55959def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
960 """When a dependency prefixed with + is added to a DEPS file, we
961 want to make sure that the change is reviewed by an OWNER of the
962 target file or directory, to avoid layering violations from being
963 introduced. This check verifies that this happens.
964 """
965 changed_lines = set()
966 for f in input_api.AffectedFiles():
967 filename = input_api.os_path.basename(f.LocalPath())
968 if filename == 'DEPS':
969 changed_lines |= set(line.strip()
970 for line_num, line
971 in f.ChangedContents())
972 if not changed_lines:
973 return []
974
[email protected]14a6131c2014-01-08 01:15:41975 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
976 changed_lines)
[email protected]e871964c2013-05-13 14:14:55977 if not virtual_depended_on_files:
978 return []
979
980 if input_api.is_committing:
981 if input_api.tbr:
982 return [output_api.PresubmitNotifyResult(
983 '--tbr was specified, skipping OWNERS check for DEPS additions')]
984 if not input_api.change.issue:
985 return [output_api.PresubmitError(
986 "DEPS approval by OWNERS check failed: this change has "
987 "no Rietveld issue number, so we can't check it for approvals.")]
988 output = output_api.PresubmitError
989 else:
990 output = output_api.PresubmitNotifyResult
991
992 owners_db = input_api.owners_db
993 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
994 input_api,
995 owners_db.email_regexp,
996 approval_needed=input_api.is_committing)
997
998 owner_email = owner_email or input_api.change.author_email
999
[email protected]de4f7d22013-05-23 14:27:461000 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511001 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461002 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551003 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1004 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411005
1006 # We strip the /DEPS part that was added by
1007 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1008 # directory.
1009 def StripDeps(path):
1010 start_deps = path.rfind('/DEPS')
1011 if start_deps != -1:
1012 return path[:start_deps]
1013 else:
1014 return path
1015 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551016 for path in missing_files]
1017
1018 if unapproved_dependencies:
1019 output_list = [
[email protected]14a6131c2014-01-08 01:15:411020 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551021 '\n '.join(sorted(unapproved_dependencies)))]
1022 if not input_api.is_committing:
1023 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1024 output_list.append(output(
1025 'Suggested missing target path OWNERS:\n %s' %
1026 '\n '.join(suggested_owners or [])))
1027 return output_list
1028
1029 return []
1030
1031
[email protected]85218562013-11-22 07:41:401032def _CheckSpamLogging(input_api, output_api):
1033 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1034 black_list = (_EXCLUDED_PATHS +
1035 _TEST_CODE_EXCLUDED_PATHS +
1036 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501037 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191038 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481039 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461040 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121041 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1042 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581043 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161044 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031045 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151046 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1047 r"^chromecast[\\\/]",
1048 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311049 r"^components[\\\/]html_viewer[\\\/]"
1050 r"web_test_delegate_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251051 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1052 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111053 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151054 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111055 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521056 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501057 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361058 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311059 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131060 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441061 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021062 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441063 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401064 source_file_filter = lambda x: input_api.FilterSourceFile(
1065 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1066
1067 log_info = []
1068 printf = []
1069
1070 for f in input_api.AffectedSourceFiles(source_file_filter):
1071 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471072 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401073 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471074 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131075 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371076
mohan.reddyf21db962014-10-16 12:26:471077 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371078 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471079 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401080 printf.append(f.LocalPath())
1081
1082 if log_info:
1083 return [output_api.PresubmitError(
1084 'These files spam the console log with LOG(INFO):',
1085 items=log_info)]
1086 if printf:
1087 return [output_api.PresubmitError(
1088 'These files spam the console log with printf/fprintf:',
1089 items=printf)]
1090 return []
1091
1092
[email protected]49aa76a2013-12-04 06:59:161093def _CheckForAnonymousVariables(input_api, output_api):
1094 """These types are all expected to hold locks while in scope and
1095 so should never be anonymous (which causes them to be immediately
1096 destroyed)."""
1097 they_who_must_be_named = [
1098 'base::AutoLock',
1099 'base::AutoReset',
1100 'base::AutoUnlock',
1101 'SkAutoAlphaRestore',
1102 'SkAutoBitmapShaderInstall',
1103 'SkAutoBlitterChoose',
1104 'SkAutoBounderCommit',
1105 'SkAutoCallProc',
1106 'SkAutoCanvasRestore',
1107 'SkAutoCommentBlock',
1108 'SkAutoDescriptor',
1109 'SkAutoDisableDirectionCheck',
1110 'SkAutoDisableOvalCheck',
1111 'SkAutoFree',
1112 'SkAutoGlyphCache',
1113 'SkAutoHDC',
1114 'SkAutoLockColors',
1115 'SkAutoLockPixels',
1116 'SkAutoMalloc',
1117 'SkAutoMaskFreeImage',
1118 'SkAutoMutexAcquire',
1119 'SkAutoPathBoundsUpdate',
1120 'SkAutoPDFRelease',
1121 'SkAutoRasterClipValidate',
1122 'SkAutoRef',
1123 'SkAutoTime',
1124 'SkAutoTrace',
1125 'SkAutoUnref',
1126 ]
1127 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1128 # bad: base::AutoLock(lock.get());
1129 # not bad: base::AutoLock lock(lock.get());
1130 bad_pattern = input_api.re.compile(anonymous)
1131 # good: new base::AutoLock(lock.get())
1132 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1133 errors = []
1134
1135 for f in input_api.AffectedFiles():
1136 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1137 continue
1138 for linenum, line in f.ChangedContents():
1139 if bad_pattern.search(line) and not good_pattern.search(line):
1140 errors.append('%s:%d' % (f.LocalPath(), linenum))
1141
1142 if errors:
1143 return [output_api.PresubmitError(
1144 'These lines create anonymous variables that need to be named:',
1145 items=errors)]
1146 return []
1147
1148
[email protected]5fe0f8742013-11-29 01:04:591149def _CheckCygwinShell(input_api, output_api):
1150 source_file_filter = lambda x: input_api.FilterSourceFile(
1151 x, white_list=(r'.+\.(gyp|gypi)$',))
1152 cygwin_shell = []
1153
1154 for f in input_api.AffectedSourceFiles(source_file_filter):
1155 for linenum, line in f.ChangedContents():
1156 if 'msvs_cygwin_shell' in line:
1157 cygwin_shell.append(f.LocalPath())
1158 break
1159
1160 if cygwin_shell:
1161 return [output_api.PresubmitError(
1162 'These files should not use msvs_cygwin_shell (the default is 0):',
1163 items=cygwin_shell)]
1164 return []
1165
[email protected]85218562013-11-22 07:41:401166
[email protected]999261d2014-03-03 20:08:081167def _CheckUserActionUpdate(input_api, output_api):
1168 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521169 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081170 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521171 # If actions.xml is already included in the changelist, the PRESUBMIT
1172 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081173 return []
1174
[email protected]999261d2014-03-03 20:08:081175 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1176 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521177 current_actions = None
[email protected]999261d2014-03-03 20:08:081178 for f in input_api.AffectedFiles(file_filter=file_filter):
1179 for line_num, line in f.ChangedContents():
1180 match = input_api.re.search(action_re, line)
1181 if match:
[email protected]2f92dec2014-03-07 19:21:521182 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1183 # loaded only once.
1184 if not current_actions:
1185 with open('tools/metrics/actions/actions.xml') as actions_f:
1186 current_actions = actions_f.read()
1187 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081188 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521189 action = 'name="{0}"'.format(action_name)
1190 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081191 return [output_api.PresubmitPromptWarning(
1192 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521193 'tools/metrics/actions/actions.xml. Please run '
1194 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081195 % (f.LocalPath(), line_num, action_name))]
1196 return []
1197
1198
[email protected]99171a92014-06-03 08:44:471199def _GetJSONParseError(input_api, filename, eat_comments=True):
1200 try:
1201 contents = input_api.ReadFile(filename)
1202 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131203 import sys
1204 original_sys_path = sys.path
1205 try:
1206 sys.path = sys.path + [input_api.os_path.join(
1207 input_api.PresubmitLocalPath(),
1208 'tools', 'json_comment_eater')]
1209 import json_comment_eater
1210 finally:
1211 sys.path = original_sys_path
1212 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471213
1214 input_api.json.loads(contents)
1215 except ValueError as e:
1216 return e
1217 return None
1218
1219
1220def _GetIDLParseError(input_api, filename):
1221 try:
1222 contents = input_api.ReadFile(filename)
1223 idl_schema = input_api.os_path.join(
1224 input_api.PresubmitLocalPath(),
1225 'tools', 'json_schema_compiler', 'idl_schema.py')
1226 process = input_api.subprocess.Popen(
1227 [input_api.python_executable, idl_schema],
1228 stdin=input_api.subprocess.PIPE,
1229 stdout=input_api.subprocess.PIPE,
1230 stderr=input_api.subprocess.PIPE,
1231 universal_newlines=True)
1232 (_, error) = process.communicate(input=contents)
1233 return error or None
1234 except ValueError as e:
1235 return e
1236
1237
1238def _CheckParseErrors(input_api, output_api):
1239 """Check that IDL and JSON files do not contain syntax errors."""
1240 actions = {
1241 '.idl': _GetIDLParseError,
1242 '.json': _GetJSONParseError,
1243 }
1244 # These paths contain test data and other known invalid JSON files.
1245 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491246 r'test[\\\/]data[\\\/]',
1247 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471248 ]
1249 # Most JSON files are preprocessed and support comments, but these do not.
1250 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491251 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471252 ]
1253 # Only run IDL checker on files in these directories.
1254 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491255 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1256 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471257 ]
1258
1259 def get_action(affected_file):
1260 filename = affected_file.LocalPath()
1261 return actions.get(input_api.os_path.splitext(filename)[1])
1262
1263 def MatchesFile(patterns, path):
1264 for pattern in patterns:
1265 if input_api.re.search(pattern, path):
1266 return True
1267 return False
1268
1269 def FilterFile(affected_file):
1270 action = get_action(affected_file)
1271 if not action:
1272 return False
1273 path = affected_file.LocalPath()
1274
1275 if MatchesFile(excluded_patterns, path):
1276 return False
1277
1278 if (action == _GetIDLParseError and
1279 not MatchesFile(idl_included_patterns, path)):
1280 return False
1281 return True
1282
1283 results = []
1284 for affected_file in input_api.AffectedFiles(
1285 file_filter=FilterFile, include_deletes=False):
1286 action = get_action(affected_file)
1287 kwargs = {}
1288 if (action == _GetJSONParseError and
1289 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1290 kwargs['eat_comments'] = False
1291 parse_error = action(input_api,
1292 affected_file.AbsoluteLocalPath(),
1293 **kwargs)
1294 if parse_error:
1295 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1296 (affected_file.LocalPath(), parse_error)))
1297 return results
1298
1299
[email protected]760deea2013-12-10 19:33:491300def _CheckJavaStyle(input_api, output_api):
1301 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471302 import sys
[email protected]760deea2013-12-10 19:33:491303 original_sys_path = sys.path
1304 try:
1305 sys.path = sys.path + [input_api.os_path.join(
1306 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1307 import checkstyle
1308 finally:
1309 # Restore sys.path to what it was before.
1310 sys.path = original_sys_path
1311
1312 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091313 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511314 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491315
1316
dskiba88634f4e2015-08-14 23:03:291317def _CheckAndroidToastUsage(input_api, output_api):
1318 """Checks that code uses org.chromium.ui.widget.Toast instead of
1319 android.widget.Toast (Chromium Toast doesn't force hardware
1320 acceleration on low-end devices, saving memory).
1321 """
1322 toast_import_pattern = input_api.re.compile(
1323 r'^import android\.widget\.Toast;$')
1324
1325 errors = []
1326
1327 sources = lambda affected_file: input_api.FilterSourceFile(
1328 affected_file,
1329 black_list=(_EXCLUDED_PATHS +
1330 _TEST_CODE_EXCLUDED_PATHS +
1331 input_api.DEFAULT_BLACK_LIST +
1332 (r'^chromecast[\\\/].*',
1333 r'^remoting[\\\/].*')),
1334 white_list=(r'.*\.java$',))
1335
1336 for f in input_api.AffectedSourceFiles(sources):
1337 for line_num, line in f.ChangedContents():
1338 if toast_import_pattern.search(line):
1339 errors.append("%s:%d" % (f.LocalPath(), line_num))
1340
1341 results = []
1342
1343 if errors:
1344 results.append(output_api.PresubmitError(
1345 'android.widget.Toast usage is detected. Android toasts use hardware'
1346 ' acceleration, and can be\ncostly on low-end devices. Please use'
1347 ' org.chromium.ui.widget.Toast instead.\n'
1348 'Contact [email protected] if you have any questions.',
1349 errors))
1350
1351 return results
1352
1353
dgnaa68d5e2015-06-10 10:08:221354def _CheckAndroidCrLogUsage(input_api, output_api):
1355 """Checks that new logs using org.chromium.base.Log:
1356 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511357 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221358 """
1359 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121360 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1361 class_in_base_pattern = input_api.re.compile(
1362 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1363 has_some_log_import_pattern = input_api.re.compile(
1364 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221365 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121366 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221367 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511368 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221369 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221370
Vincent Scheib16d7b272015-09-15 18:09:071371 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221372 'or contact [email protected] for more info.')
1373 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121374
dgnaa68d5e2015-06-10 10:08:221375 tag_decl_errors = []
1376 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121377 tag_errors = []
dgn38736db2015-09-18 19:20:511378 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121379 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221380
1381 for f in input_api.AffectedSourceFiles(sources):
1382 file_content = input_api.ReadFile(f)
1383 has_modified_logs = False
1384
1385 # Per line checks
dgn87d9fb62015-06-12 09:15:121386 if (cr_log_import_pattern.search(file_content) or
1387 (class_in_base_pattern.search(file_content) and
1388 not has_some_log_import_pattern.search(file_content))):
1389 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221390 for line_num, line in f.ChangedContents():
1391
1392 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121393 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221394 if match:
1395 has_modified_logs = True
1396
1397 # Make sure it uses "TAG"
1398 if not match.group('tag') == 'TAG':
1399 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121400 else:
1401 # Report non cr Log function calls in changed lines
1402 for line_num, line in f.ChangedContents():
1403 if log_call_pattern.search(line):
1404 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221405
1406 # Per file checks
1407 if has_modified_logs:
1408 # Make sure the tag is using the "cr" prefix and is not too long
1409 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511410 tag_name = match.group('name') if match else None
1411 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221412 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511413 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221414 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511415 elif '.' in tag_name:
1416 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221417
1418 results = []
1419 if tag_decl_errors:
1420 results.append(output_api.PresubmitPromptWarning(
1421 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511422 '"private static final String TAG = "<package tag>".\n'
1423 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221424 tag_decl_errors))
1425
1426 if tag_length_errors:
1427 results.append(output_api.PresubmitError(
1428 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511429 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221430 tag_length_errors))
1431
1432 if tag_errors:
1433 results.append(output_api.PresubmitPromptWarning(
1434 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1435 tag_errors))
1436
dgn87d9fb62015-06-12 09:15:121437 if util_log_errors:
dgn4401aa52015-04-29 16:26:171438 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121439 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1440 util_log_errors))
1441
dgn38736db2015-09-18 19:20:511442 if tag_with_dot_errors:
1443 results.append(output_api.PresubmitPromptWarning(
1444 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1445 tag_with_dot_errors))
1446
dgn4401aa52015-04-29 16:26:171447 return results
1448
1449
mnaganov9b9b1fe82014-12-11 16:30:361450def _CheckForCopyrightedCode(input_api, output_api):
1451 """Verifies that newly added code doesn't contain copyrighted material
1452 and is properly licensed under the standard Chromium license.
1453
1454 As there can be false positives, we maintain a whitelist file. This check
1455 also verifies that the whitelist file is up to date.
1456 """
1457 import sys
1458 original_sys_path = sys.path
1459 try:
1460 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221461 input_api.PresubmitLocalPath(), 'tools')]
1462 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361463 finally:
1464 # Restore sys.path to what it was before.
1465 sys.path = original_sys_path
1466
1467 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1468
1469
glidere61efad2015-02-18 17:39:431470def _CheckSingletonInHeaders(input_api, output_api):
1471 """Checks to make sure no header files have |Singleton<|."""
1472 def FileFilter(affected_file):
1473 # It's ok for base/memory/singleton.h to have |Singleton<|.
1474 black_list = (_EXCLUDED_PATHS +
1475 input_api.DEFAULT_BLACK_LIST +
1476 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1477 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1478
sergeyu34d21222015-09-16 00:11:441479 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431480 files = []
1481 for f in input_api.AffectedSourceFiles(FileFilter):
1482 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1483 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1484 contents = input_api.ReadFile(f)
1485 for line in contents.splitlines(False):
1486 if (not input_api.re.match(r'//', line) and # Strip C++ comment.
1487 pattern.search(line)):
1488 files.append(f)
1489 break
1490
1491 if files:
1492 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441493 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431494 'Please move them to an appropriate source file so that the ' +
1495 'template gets instantiated in a single compilation unit.',
1496 files) ]
1497 return []
1498
1499
[email protected]fd20b902014-05-09 02:14:531500_DEPRECATED_CSS = [
1501 # Values
1502 ( "-webkit-box", "flex" ),
1503 ( "-webkit-inline-box", "inline-flex" ),
1504 ( "-webkit-flex", "flex" ),
1505 ( "-webkit-inline-flex", "inline-flex" ),
1506 ( "-webkit-min-content", "min-content" ),
1507 ( "-webkit-max-content", "max-content" ),
1508
1509 # Properties
1510 ( "-webkit-background-clip", "background-clip" ),
1511 ( "-webkit-background-origin", "background-origin" ),
1512 ( "-webkit-background-size", "background-size" ),
1513 ( "-webkit-box-shadow", "box-shadow" ),
1514
1515 # Functions
1516 ( "-webkit-gradient", "gradient" ),
1517 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1518 ( "-webkit-linear-gradient", "linear-gradient" ),
1519 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1520 ( "-webkit-radial-gradient", "radial-gradient" ),
1521 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1522]
1523
1524def _CheckNoDeprecatedCSS(input_api, output_api):
1525 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251526 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341527 documentation and iOS CSS for dom distiller
1528 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251529 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531530 results = []
dbeam070cfe62014-10-22 06:44:021531 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251532 black_list = (_EXCLUDED_PATHS +
1533 _TEST_CODE_EXCLUDED_PATHS +
1534 input_api.DEFAULT_BLACK_LIST +
1535 (r"^chrome/common/extensions/docs",
1536 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341537 r"^components/dom_distiller/core/css/distilledpage_ios.css",
[email protected]9a48e3f82014-05-22 00:06:251538 r"^native_client_sdk"))
1539 file_filter = lambda f: input_api.FilterSourceFile(
1540 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531541 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1542 for line_num, line in fpath.ChangedContents():
1543 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021544 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531545 results.append(output_api.PresubmitError(
1546 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1547 (fpath.LocalPath(), line_num, deprecated_value, value)))
1548 return results
1549
mohan.reddyf21db962014-10-16 12:26:471550
dbeam070cfe62014-10-22 06:44:021551_DEPRECATED_JS = [
1552 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1553 ( "__defineGetter__", "Object.defineProperty" ),
1554 ( "__defineSetter__", "Object.defineProperty" ),
1555]
1556
1557def _CheckNoDeprecatedJS(input_api, output_api):
1558 """Make sure that we don't use deprecated JS in Chrome code."""
1559 results = []
1560 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1561 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1562 input_api.DEFAULT_BLACK_LIST)
1563 file_filter = lambda f: input_api.FilterSourceFile(
1564 f, white_list=file_inclusion_pattern, black_list=black_list)
1565 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1566 for lnum, line in fpath.ChangedContents():
1567 for (deprecated, replacement) in _DEPRECATED_JS:
1568 if deprecated in line:
1569 results.append(output_api.PresubmitError(
1570 "%s:%d: Use of deprecated JS %s, use %s instead" %
1571 (fpath.LocalPath(), lnum, deprecated, replacement)))
1572 return results
1573
1574
dgnaa68d5e2015-06-10 10:08:221575def _AndroidSpecificOnUploadChecks(input_api, output_api):
1576 """Groups checks that target android code."""
1577 results = []
dgnaa68d5e2015-06-10 10:08:221578 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291579 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221580 return results
1581
1582
[email protected]22c9bd72011-03-27 16:47:391583def _CommonChecks(input_api, output_api):
1584 """Checks common to both upload and commit."""
1585 results = []
1586 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381587 input_api, output_api,
1588 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461589 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191590 results.extend(
[email protected]760deea2013-12-10 19:33:491591 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541592 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181593 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221594 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441595 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591596 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061597 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121598 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181599 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221600 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491601 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271602 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031603 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491604 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441605 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271606 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541607 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441608 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461609 # TODO(danakj): Remove this when base/move.h is removed.
1610 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551611 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041612 results.extend(
1613 input_api.canned_checks.CheckChangeHasNoTabs(
1614 input_api,
1615 output_api,
1616 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401617 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161618 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591619 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081620 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531621 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021622 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471623 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041624 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361625 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231626 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431627 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241628
1629 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1630 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1631 input_api, output_api,
1632 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381633 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391634 return results
[email protected]1f7b4172010-01-28 01:17:341635
[email protected]b337cb5b2011-01-23 21:24:051636
[email protected]66daa702011-05-28 14:41:461637def _CheckAuthorizedAuthor(input_api, output_api):
1638 """For non-googler/chromites committers, verify the author's email address is
1639 in AUTHORS.
1640 """
[email protected]9bb9cb82011-06-13 20:43:011641 # TODO(maruel): Add it to input_api?
1642 import fnmatch
1643
[email protected]66daa702011-05-28 14:41:461644 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011645 if not author:
1646 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461647 return []
[email protected]c99663292011-05-31 19:46:081648 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461649 input_api.PresubmitLocalPath(), 'AUTHORS')
1650 valid_authors = (
1651 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1652 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181653 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441654 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231655 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461656 return [output_api.PresubmitPromptWarning(
1657 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1658 '\n'
1659 'http://www.chromium.org/developers/contributing-code and read the '
1660 '"Legal" section\n'
1661 'If you are a chromite, verify the contributor signed the CLA.') %
1662 author)]
1663 return []
1664
1665
[email protected]b8079ae4a2012-12-05 19:56:491666def _CheckPatchFiles(input_api, output_api):
1667 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1668 if f.LocalPath().endswith(('.orig', '.rej'))]
1669 if problems:
1670 return [output_api.PresubmitError(
1671 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031672 else:
1673 return []
[email protected]b8079ae4a2012-12-05 19:56:491674
1675
[email protected]b00342e7f2013-03-26 16:21:541676def _DidYouMeanOSMacro(bad_macro):
1677 try:
1678 return {'A': 'OS_ANDROID',
1679 'B': 'OS_BSD',
1680 'C': 'OS_CHROMEOS',
1681 'F': 'OS_FREEBSD',
1682 'L': 'OS_LINUX',
1683 'M': 'OS_MACOSX',
1684 'N': 'OS_NACL',
1685 'O': 'OS_OPENBSD',
1686 'P': 'OS_POSIX',
1687 'S': 'OS_SOLARIS',
1688 'W': 'OS_WIN'}[bad_macro[3].upper()]
1689 except KeyError:
1690 return ''
1691
1692
1693def _CheckForInvalidOSMacrosInFile(input_api, f):
1694 """Check for sensible looking, totally invalid OS macros."""
1695 preprocessor_statement = input_api.re.compile(r'^\s*#')
1696 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1697 results = []
1698 for lnum, line in f.ChangedContents():
1699 if preprocessor_statement.search(line):
1700 for match in os_macro.finditer(line):
1701 if not match.group(1) in _VALID_OS_MACROS:
1702 good = _DidYouMeanOSMacro(match.group(1))
1703 did_you_mean = ' (did you mean %s?)' % good if good else ''
1704 results.append(' %s:%d %s%s' % (f.LocalPath(),
1705 lnum,
1706 match.group(1),
1707 did_you_mean))
1708 return results
1709
1710
1711def _CheckForInvalidOSMacros(input_api, output_api):
1712 """Check all affected files for invalid OS macros."""
1713 bad_macros = []
1714 for f in input_api.AffectedFiles():
1715 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1716 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1717
1718 if not bad_macros:
1719 return []
1720
1721 return [output_api.PresubmitError(
1722 'Possibly invalid OS macro[s] found. Please fix your code\n'
1723 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1724
lliabraa35bab3932014-10-01 12:16:441725
1726def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1727 """Check all affected files for invalid "if defined" macros."""
1728 ALWAYS_DEFINED_MACROS = (
1729 "TARGET_CPU_PPC",
1730 "TARGET_CPU_PPC64",
1731 "TARGET_CPU_68K",
1732 "TARGET_CPU_X86",
1733 "TARGET_CPU_ARM",
1734 "TARGET_CPU_MIPS",
1735 "TARGET_CPU_SPARC",
1736 "TARGET_CPU_ALPHA",
1737 "TARGET_IPHONE_SIMULATOR",
1738 "TARGET_OS_EMBEDDED",
1739 "TARGET_OS_IPHONE",
1740 "TARGET_OS_MAC",
1741 "TARGET_OS_UNIX",
1742 "TARGET_OS_WIN32",
1743 )
1744 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1745 results = []
1746 for lnum, line in f.ChangedContents():
1747 for match in ifdef_macro.finditer(line):
1748 if match.group(1) in ALWAYS_DEFINED_MACROS:
1749 always_defined = ' %s is always defined. ' % match.group(1)
1750 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1751 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1752 lnum,
1753 always_defined,
1754 did_you_mean))
1755 return results
1756
1757
1758def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1759 """Check all affected files for invalid "if defined" macros."""
1760 bad_macros = []
1761 for f in input_api.AffectedFiles():
1762 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1763 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1764
1765 if not bad_macros:
1766 return []
1767
1768 return [output_api.PresubmitError(
1769 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1770 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1771 bad_macros)]
1772
1773
danakj3c84d0c2014-10-06 15:35:461774def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1775 """Check all affected files for using side effects of Pass."""
1776 errors = []
1777 for f in input_api.AffectedFiles():
1778 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1779 for lnum, line in f.ChangedContents():
1780 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471781 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461782 errors.append(output_api.PresubmitError(
1783 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1784 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1785 return errors
1786
1787
mlamouria82272622014-09-16 18:45:041788def _CheckForIPCRules(input_api, output_api):
1789 """Check for same IPC rules described in
1790 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1791 """
1792 base_pattern = r'IPC_ENUM_TRAITS\('
1793 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1794 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1795
1796 problems = []
1797 for f in input_api.AffectedSourceFiles(None):
1798 local_path = f.LocalPath()
1799 if not local_path.endswith('.h'):
1800 continue
1801 for line_number, line in f.ChangedContents():
1802 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1803 problems.append(
1804 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1805
1806 if problems:
1807 return [output_api.PresubmitPromptWarning(
1808 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1809 else:
1810 return []
1811
[email protected]b00342e7f2013-03-26 16:21:541812
mostynbb639aca52015-01-07 20:31:231813def _CheckForWindowsLineEndings(input_api, output_api):
1814 """Check source code and known ascii text files for Windows style line
1815 endings.
1816 """
earthdok1b5e0ee2015-03-10 15:19:101817 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231818
1819 file_inclusion_pattern = (
1820 known_text_files,
1821 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1822 )
1823
1824 filter = lambda f: input_api.FilterSourceFile(
1825 f, white_list=file_inclusion_pattern, black_list=None)
1826 files = [f.LocalPath() for f in
1827 input_api.AffectedSourceFiles(filter)]
1828
1829 problems = []
1830
1831 for file in files:
1832 fp = open(file, 'r')
1833 for line in fp:
1834 if line.endswith('\r\n'):
1835 problems.append(file)
1836 break
1837 fp.close()
1838
1839 if problems:
1840 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1841 'these files to contain Windows style line endings?\n' +
1842 '\n'.join(problems))]
1843
1844 return []
1845
1846
[email protected]1f7b4172010-01-28 01:17:341847def CheckChangeOnUpload(input_api, output_api):
1848 results = []
1849 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471850 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171851 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281852 results.extend(
1853 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191854 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221855 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541856 return results
[email protected]ca8d19842009-02-19 16:33:121857
1858
[email protected]1bfb8322014-04-23 01:02:411859def GetTryServerMasterForBot(bot):
1860 """Returns the Try Server master for the given bot.
1861
[email protected]0bb112362014-07-26 04:38:321862 It tries to guess the master from the bot name, but may still fail
1863 and return None. There is no longer a default master.
1864 """
1865 # Potentially ambiguous bot names are listed explicitly.
1866 master_map = {
[email protected]0bb112362014-07-26 04:38:321867 'chromium_presubmit': 'tryserver.chromium.linux',
1868 'blink_presubmit': 'tryserver.chromium.linux',
1869 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411870 }
[email protected]0bb112362014-07-26 04:38:321871 master = master_map.get(bot)
1872 if not master:
sergiyb37fd293f2015-02-26 06:55:011873 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321874 master = 'tryserver.chromium.linux'
1875 elif 'win' in bot:
1876 master = 'tryserver.chromium.win'
1877 elif 'mac' in bot or 'ios' in bot:
1878 master = 'tryserver.chromium.mac'
1879 return master
[email protected]1bfb8322014-04-23 01:02:411880
1881
Paweł Hajdan, Jr55083782014-12-19 20:32:561882def GetDefaultTryConfigs(bots):
1883 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011884 """
1885
Paweł Hajdan, Jr55083782014-12-19 20:32:561886 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411887
1888 # Build up the mapping from tryserver master to bot/test.
1889 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561890 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411891 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1892 return out
[email protected]38c6a512013-12-18 23:48:011893
1894
[email protected]ca8d19842009-02-19 16:33:121895def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541896 results = []
[email protected]1f7b4172010-01-28 01:17:341897 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511898 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1899 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1900 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541901 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271902 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341903 input_api,
1904 output_api,
[email protected]2fdd1f362013-01-16 03:56:031905 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271906
[email protected]3e4eb112011-01-18 03:29:541907 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1908 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411909 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1910 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541911 return results
[email protected]ca8d19842009-02-19 16:33:121912
1913
[email protected]7468ac522014-03-12 23:35:571914def GetPreferredTryMasters(project, change):
Paweł Hajdan, Jref2afd42015-01-07 15:59:521915 import json
sergiyb57a71e32015-06-03 18:44:001916 import os.path
1917 import platform
1918 import subprocess
smut3ef206e12015-03-20 09:30:001919
sergiyb57a71e32015-06-03 18:44:001920 cq_config_path = os.path.join(
1921 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
1922 # commit_queue.py below is a script in depot_tools directory, which has a
1923 # 'builders' command to retrieve a list of CQ builders from the CQ config.
1924 is_win = platform.system() == 'Windows'
1925 masters = json.loads(subprocess.check_output(
1926 ['commit_queue', 'builders', cq_config_path], shell=is_win))
[email protected]911753b2012-08-02 12:11:541927
sergiyb6092f742015-06-16 09:00:521928 try_config = {}
1929 for master in masters:
1930 try_config.setdefault(master, {})
1931 for builder in masters[master]:
sergiyb57a71e32015-06-03 18:44:001932 # Do not trigger presubmit builders, since they're likely to fail
1933 # (e.g. OWNERS checks before finished code review), and we're
1934 # running local presubmit anyway.
sergiyb6092f742015-06-16 09:00:521935 if 'presubmit' not in builder:
1936 try_config[master][builder] = ['defaulttests']
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321937
sergiyb6092f742015-06-16 09:00:521938 return try_config