blob: 294ee1793ad0f0aac1688fc0be6335ba35ec23ad [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
[email protected]4306417642009-06-11 00:33:4026)
[email protected]ca8d19842009-02-19 16:33:1227
jochen9ea8fdbc2014-09-25 13:21:3528# The NetscapePlugIn library is excluded from pan-project as it will soon
29# be deleted together with the rest of the NPAPI and it's not worthwhile to
30# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3831_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3232 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3833)
34
[email protected]06e6d0ff2012-12-11 01:36:4435# Fragment of a regular expression that matches C++ and Objective-C++
36# implementation files.
37_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
38
39# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3244 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4450 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4951 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4752 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4953 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0854 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4955 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4456)
[email protected]ca8d19842009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
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',
277 'OS_BSD',
278 'OS_CAT', # For testing.
279 'OS_CHROMEOS',
280 'OS_FREEBSD',
281 'OS_IOS',
282 'OS_LINUX',
283 'OS_MACOSX',
284 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21285 'OS_NACL_NONSFI',
286 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54287 'OS_OPENBSD',
288 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37289 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54290 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54291 'OS_WIN',
292)
293
294
[email protected]55459852011-08-10 15:17:19295def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
296 """Attempts to prevent use of functions intended only for testing in
297 non-testing code. For now this is just a best-effort implementation
298 that ignores header files and may have some false positives. A
299 better implementation would probably need a proper C++ parser.
300 """
301 # We only scan .cc files and the like, as the declaration of
302 # for-testing functions in header files are hard to distinguish from
303 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44304 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19305
jochenc0d4808c2015-07-27 09:25:42306 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19307 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09308 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19309 exclusion_pattern = input_api.re.compile(
310 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
311 base_function_pattern, base_function_pattern))
312
313 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44314 black_list = (_EXCLUDED_PATHS +
315 _TEST_CODE_EXCLUDED_PATHS +
316 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19317 return input_api.FilterSourceFile(
318 affected_file,
319 white_list=(file_inclusion_pattern, ),
320 black_list=black_list)
321
322 problems = []
323 for f in input_api.AffectedSourceFiles(FilterFile):
324 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24325 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03326 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46327 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03328 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19329 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03330 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19331
332 if problems:
[email protected]f7051d52013-04-02 18:31:42333 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03334 else:
335 return []
[email protected]55459852011-08-10 15:17:19336
337
[email protected]10689ca2011-09-02 02:31:54338def _CheckNoIOStreamInHeaders(input_api, output_api):
339 """Checks to make sure no .h files include <iostream>."""
340 files = []
341 pattern = input_api.re.compile(r'^#include\s*<iostream>',
342 input_api.re.MULTILINE)
343 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
344 if not f.LocalPath().endswith('.h'):
345 continue
346 contents = input_api.ReadFile(f)
347 if pattern.search(contents):
348 files.append(f)
349
350 if len(files):
351 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06352 'Do not #include <iostream> in header files, since it inserts static '
353 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54354 '#include <ostream>. See http://crbug.com/94794',
355 files) ]
356 return []
357
358
[email protected]72df4e782012-06-21 16:28:18359def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52360 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18361 problems = []
362 for f in input_api.AffectedFiles():
363 if (not f.LocalPath().endswith(('.cc', '.mm'))):
364 continue
365
366 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04367 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18368 problems.append(' %s:%d' % (f.LocalPath(), line_num))
369
370 if not problems:
371 return []
372 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
373 '\n'.join(problems))]
374
375
danakj61c1aa22015-10-26 19:55:52376def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
377 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
378 errors = []
379 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
380 input_api.re.MULTILINE)
381 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
382 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
383 continue
384 for lnum, line in f.ChangedContents():
385 if input_api.re.search(pattern, line):
386 errors.append(output_api.PresubmitError(
387 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
388 'DCHECK_IS_ON()", not forgetting the braces.')
389 % (f.LocalPath(), lnum)))
390 return errors
391
392
mcasasb7440c282015-02-04 14:52:19393def _FindHistogramNameInLine(histogram_name, line):
394 """Tries to find a histogram name or prefix in a line."""
395 if not "affected-histogram" in line:
396 return histogram_name in line
397 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
398 # the histogram_name.
399 if not '"' in line:
400 return False
401 histogram_prefix = line.split('\"')[1]
402 return histogram_prefix in histogram_name
403
404
405def _CheckUmaHistogramChanges(input_api, output_api):
406 """Check that UMA histogram names in touched lines can still be found in other
407 lines of the patch or in histograms.xml. Note that this check would not catch
408 the reverse: changes in histograms.xml not matched in the code itself."""
409 touched_histograms = []
410 histograms_xml_modifications = []
411 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
412 for f in input_api.AffectedFiles():
413 # If histograms.xml itself is modified, keep the modified lines for later.
414 if f.LocalPath().endswith(('histograms.xml')):
415 histograms_xml_modifications = f.ChangedContents()
416 continue
417 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
418 continue
419 for line_num, line in f.ChangedContents():
420 found = pattern.search(line)
421 if found:
422 touched_histograms.append([found.group(1), f, line_num])
423
424 # Search for the touched histogram names in the local modifications to
425 # histograms.xml, and, if not found, on the base histograms.xml file.
426 unmatched_histograms = []
427 for histogram_info in touched_histograms:
428 histogram_name_found = False
429 for line_num, line in histograms_xml_modifications:
430 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
431 if histogram_name_found:
432 break
433 if not histogram_name_found:
434 unmatched_histograms.append(histogram_info)
435
eromanb90c82e7e32015-04-01 15:13:49436 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19437 problems = []
438 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49439 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19440 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45441 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19442 histogram_name_found = False
443 for line in histograms_xml:
444 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
445 if histogram_name_found:
446 break
447 if not histogram_name_found:
448 problems.append(' [%s:%d] %s' %
449 (f.LocalPath(), line_num, histogram_name))
450
451 if not problems:
452 return []
453 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
454 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49455 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19456
457
[email protected]8ea5d4b2011-09-13 21:49:22458def _CheckNoNewWStrings(input_api, output_api):
459 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27460 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22461 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20462 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57463 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
464 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20465 continue
[email protected]8ea5d4b2011-09-13 21:49:22466
[email protected]a11dbe9b2012-08-07 01:32:58467 allowWString = False
[email protected]b5c24292011-11-28 14:38:20468 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58469 if 'presubmit: allow wstring' in line:
470 allowWString = True
471 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27472 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58473 allowWString = False
474 else:
475 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22476
[email protected]55463aa62011-10-12 00:48:27477 if not problems:
478 return []
479 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58480 ' If you are calling a cross-platform API that accepts a wstring, '
481 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27482 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22483
484
[email protected]2a8ac9c2011-10-19 17:20:44485def _CheckNoDEPSGIT(input_api, output_api):
486 """Make sure .DEPS.git is never modified manually."""
487 if any(f.LocalPath().endswith('.DEPS.git') for f in
488 input_api.AffectedFiles()):
489 return [output_api.PresubmitError(
490 'Never commit changes to .DEPS.git. This file is maintained by an\n'
491 'automated system based on what\'s in DEPS and your changes will be\n'
492 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34493 '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:44494 'for more information')]
495 return []
496
497
tandriief664692014-09-23 14:51:47498def _CheckValidHostsInDEPS(input_api, output_api):
499 """Checks that DEPS file deps are from allowed_hosts."""
500 # Run only if DEPS file has been modified to annoy fewer bystanders.
501 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
502 return []
503 # Outsource work to gclient verify
504 try:
505 input_api.subprocess.check_output(['gclient', 'verify'])
506 return []
507 except input_api.subprocess.CalledProcessError, error:
508 return [output_api.PresubmitError(
509 'DEPS file must have only git dependencies.',
510 long_text=error.output)]
511
512
[email protected]127f18ec2012-06-16 05:05:59513def _CheckNoBannedFunctions(input_api, output_api):
514 """Make sure that banned functions are not used."""
515 warnings = []
516 errors = []
517
518 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
519 for f in input_api.AffectedFiles(file_filter=file_filter):
520 for line_num, line in f.ChangedContents():
521 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26522 matched = False
523 if func_name[0:1] == '/':
524 regex = func_name[1:]
525 if input_api.re.search(regex, line):
526 matched = True
527 elif func_name in line:
528 matched = True
529 if matched:
[email protected]127f18ec2012-06-16 05:05:59530 problems = warnings;
531 if error:
532 problems = errors;
533 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
534 for message_line in message:
535 problems.append(' %s' % message_line)
536
537 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
538 for f in input_api.AffectedFiles(file_filter=file_filter):
539 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49540 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
541 def IsBlacklisted(affected_file, blacklist):
542 local_path = affected_file.LocalPath()
543 for item in blacklist:
544 if input_api.re.match(item, local_path):
545 return True
546 return False
547 if IsBlacklisted(f, excluded_paths):
548 continue
[email protected]d89eec82013-12-03 14:10:59549 matched = False
550 if func_name[0:1] == '/':
551 regex = func_name[1:]
552 if input_api.re.search(regex, line):
553 matched = True
554 elif func_name in line:
555 matched = True
556 if matched:
[email protected]127f18ec2012-06-16 05:05:59557 problems = warnings;
558 if error:
559 problems = errors;
560 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
561 for message_line in message:
562 problems.append(' %s' % message_line)
563
564 result = []
565 if (warnings):
566 result.append(output_api.PresubmitPromptWarning(
567 'Banned functions were used.\n' + '\n'.join(warnings)))
568 if (errors):
569 result.append(output_api.PresubmitError(
570 'Banned functions were used.\n' + '\n'.join(errors)))
571 return result
572
573
[email protected]6c063c62012-07-11 19:11:06574def _CheckNoPragmaOnce(input_api, output_api):
575 """Make sure that banned functions are not used."""
576 files = []
577 pattern = input_api.re.compile(r'^#pragma\s+once',
578 input_api.re.MULTILINE)
579 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
580 if not f.LocalPath().endswith('.h'):
581 continue
582 contents = input_api.ReadFile(f)
583 if pattern.search(contents):
584 files.append(f)
585
586 if files:
587 return [output_api.PresubmitError(
588 'Do not use #pragma once in header files.\n'
589 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
590 files)]
591 return []
592
[email protected]127f18ec2012-06-16 05:05:59593
[email protected]e7479052012-09-19 00:26:12594def _CheckNoTrinaryTrueFalse(input_api, output_api):
595 """Checks to make sure we don't introduce use of foo ? true : false."""
596 problems = []
597 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
598 for f in input_api.AffectedFiles():
599 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
600 continue
601
602 for line_num, line in f.ChangedContents():
603 if pattern.match(line):
604 problems.append(' %s:%d' % (f.LocalPath(), line_num))
605
606 if not problems:
607 return []
608 return [output_api.PresubmitPromptWarning(
609 'Please consider avoiding the "? true : false" pattern if possible.\n' +
610 '\n'.join(problems))]
611
612
[email protected]55f9f382012-07-31 11:02:18613def _CheckUnwantedDependencies(input_api, output_api):
614 """Runs checkdeps on #include statements added in this
615 change. Breaking - rules is an error, breaking ! rules is a
616 warning.
617 """
mohan.reddyf21db962014-10-16 12:26:47618 import sys
[email protected]55f9f382012-07-31 11:02:18619 # We need to wait until we have an input_api object and use this
620 # roundabout construct to import checkdeps because this file is
621 # eval-ed and thus doesn't have __file__.
622 original_sys_path = sys.path
623 try:
624 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47625 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18626 import checkdeps
627 from cpp_checker import CppChecker
628 from rules import Rule
629 finally:
630 # Restore sys.path to what it was before.
631 sys.path = original_sys_path
632
633 added_includes = []
634 for f in input_api.AffectedFiles():
635 if not CppChecker.IsCppFile(f.LocalPath()):
636 continue
637
638 changed_lines = [line for line_num, line in f.ChangedContents()]
639 added_includes.append([f.LocalPath(), changed_lines])
640
[email protected]26385172013-05-09 23:11:35641 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18642
643 error_descriptions = []
644 warning_descriptions = []
645 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
646 added_includes):
647 description_with_path = '%s\n %s' % (path, rule_description)
648 if rule_type == Rule.DISALLOW:
649 error_descriptions.append(description_with_path)
650 else:
651 warning_descriptions.append(description_with_path)
652
653 results = []
654 if error_descriptions:
655 results.append(output_api.PresubmitError(
656 'You added one or more #includes that violate checkdeps rules.',
657 error_descriptions))
658 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42659 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18660 'You added one or more #includes of files that are temporarily\n'
661 'allowed but being removed. Can you avoid introducing the\n'
662 '#include? See relevant DEPS file(s) for details and contacts.',
663 warning_descriptions))
664 return results
665
666
[email protected]fbcafe5a2012-08-08 15:31:22667def _CheckFilePermissions(input_api, output_api):
668 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15669 if input_api.platform == 'win32':
670 return []
mohan.reddyf21db962014-10-16 12:26:47671 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
672 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22673 for f in input_api.AffectedFiles():
674 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11675 try:
676 input_api.subprocess.check_output(args)
677 return []
678 except input_api.subprocess.CalledProcessError as error:
679 return [output_api.PresubmitError(
680 'checkperms.py failed:',
681 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22682
683
[email protected]c8278b32012-10-30 20:35:49684def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
685 """Makes sure we don't include ui/aura/window_property.h
686 in header files.
687 """
688 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
689 errors = []
690 for f in input_api.AffectedFiles():
691 if not f.LocalPath().endswith('.h'):
692 continue
693 for line_num, line in f.ChangedContents():
694 if pattern.match(line):
695 errors.append(' %s:%d' % (f.LocalPath(), line_num))
696
697 results = []
698 if errors:
699 results.append(output_api.PresubmitError(
700 'Header files should not include ui/aura/window_property.h', errors))
701 return results
702
703
[email protected]cf9b78f2012-11-14 11:40:28704def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
705 """Checks that the lines in scope occur in the right order.
706
707 1. C system files in alphabetical order
708 2. C++ system files in alphabetical order
709 3. Project's .h files
710 """
711
712 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
713 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
714 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
715
716 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
717
718 state = C_SYSTEM_INCLUDES
719
720 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57721 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28722 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55723 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28724 for line_num, line in scope:
725 if c_system_include_pattern.match(line):
726 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55727 problem_linenums.append((line_num, previous_line_num,
728 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28729 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55730 problem_linenums.append((line_num, previous_line_num,
731 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28732 elif cpp_system_include_pattern.match(line):
733 if state == C_SYSTEM_INCLUDES:
734 state = CPP_SYSTEM_INCLUDES
735 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55736 problem_linenums.append((line_num, previous_line_num,
737 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28738 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55739 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28740 elif custom_include_pattern.match(line):
741 if state != CUSTOM_INCLUDES:
742 state = CUSTOM_INCLUDES
743 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55744 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28745 else:
brucedawson70fadb02015-06-30 17:47:55746 problem_linenums.append((line_num, previous_line_num,
747 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28748 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57749 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28750
751 warnings = []
brucedawson70fadb02015-06-30 17:47:55752 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57753 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55754 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28755 return warnings
756
757
[email protected]ac294a12012-12-06 16:38:43758def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28759 """Checks the #include order for the given file f."""
760
[email protected]2299dcf2012-11-15 19:56:24761 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30762 # Exclude the following includes from the check:
763 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
764 # specific order.
765 # 2) <atlbase.h>, "build/build_config.h"
766 excluded_include_pattern = input_api.re.compile(
767 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24768 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33769 # Match the final or penultimate token if it is xxxtest so we can ignore it
770 # when considering the special first include.
771 test_file_tag_pattern = input_api.re.compile(
772 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11773 if_pattern = input_api.re.compile(
774 r'\s*#\s*(if|elif|else|endif|define|undef).*')
775 # Some files need specialized order of includes; exclude such files from this
776 # check.
777 uncheckable_includes_pattern = input_api.re.compile(
778 r'\s*#include '
779 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28780
781 contents = f.NewContents()
782 warnings = []
783 line_num = 0
784
[email protected]ac294a12012-12-06 16:38:43785 # Handle the special first include. If the first include file is
786 # some/path/file.h, the corresponding including file can be some/path/file.cc,
787 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
788 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33789 # If the included file is some/path/file_platform.h the including file could
790 # also be some/path/file_xxxtest_platform.h.
791 including_file_base_name = test_file_tag_pattern.sub(
792 '', input_api.os_path.basename(f.LocalPath()))
793
[email protected]ac294a12012-12-06 16:38:43794 for line in contents:
795 line_num += 1
796 if system_include_pattern.match(line):
797 # No special first include -> process the line again along with normal
798 # includes.
799 line_num -= 1
800 break
801 match = custom_include_pattern.match(line)
802 if match:
803 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33804 header_basename = test_file_tag_pattern.sub(
805 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
806
807 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24808 # No special first include -> process the line again along with normal
809 # includes.
810 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43811 break
[email protected]cf9b78f2012-11-14 11:40:28812
813 # Split into scopes: Each region between #if and #endif is its own scope.
814 scopes = []
815 current_scope = []
816 for line in contents[line_num:]:
817 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11818 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54819 continue
[email protected]2309b0fa02012-11-16 12:18:27820 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28821 scopes.append(current_scope)
822 current_scope = []
[email protected]962f117e2012-11-22 18:11:56823 elif ((system_include_pattern.match(line) or
824 custom_include_pattern.match(line)) and
825 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28826 current_scope.append((line_num, line))
827 scopes.append(current_scope)
828
829 for scope in scopes:
830 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
831 changed_linenums))
832 return warnings
833
834
835def _CheckIncludeOrder(input_api, output_api):
836 """Checks that the #include order is correct.
837
838 1. The corresponding header for source files.
839 2. C system files in alphabetical order
840 3. C++ system files in alphabetical order
841 4. Project's .h files in alphabetical order
842
[email protected]ac294a12012-12-06 16:38:43843 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
844 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28845 """
[email protected]e120b012014-08-15 19:08:35846 def FileFilterIncludeOrder(affected_file):
847 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
848 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28849
850 warnings = []
[email protected]e120b012014-08-15 19:08:35851 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08852 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43853 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
854 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28855
856 results = []
857 if warnings:
[email protected]f7051d52013-04-02 18:31:42858 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53859 warnings))
[email protected]cf9b78f2012-11-14 11:40:28860 return results
861
862
[email protected]70ca77752012-11-20 03:45:03863def _CheckForVersionControlConflictsInFile(input_api, f):
864 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
865 errors = []
866 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23867 if f.LocalPath().endswith('.md'):
868 # First-level headers in markdown look a lot like version control
869 # conflict markers. http://daringfireball.net/projects/markdown/basics
870 continue
[email protected]70ca77752012-11-20 03:45:03871 if pattern.match(line):
872 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
873 return errors
874
875
876def _CheckForVersionControlConflicts(input_api, output_api):
877 """Usually this is not intentional and will cause a compile failure."""
878 errors = []
879 for f in input_api.AffectedFiles():
880 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
881
882 results = []
883 if errors:
884 results.append(output_api.PresubmitError(
885 'Version control conflict markers found, please resolve.', errors))
886 return results
887
888
[email protected]06e6d0ff2012-12-11 01:36:44889def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
890 def FilterFile(affected_file):
891 """Filter function for use with input_api.AffectedSourceFiles,
892 below. This filters out everything except non-test files from
893 top-level directories that generally speaking should not hard-code
894 service URLs (e.g. src/android_webview/, src/content/ and others).
895 """
896 return input_api.FilterSourceFile(
897 affected_file,
[email protected]78bb39d62012-12-11 15:11:56898 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44899 black_list=(_EXCLUDED_PATHS +
900 _TEST_CODE_EXCLUDED_PATHS +
901 input_api.DEFAULT_BLACK_LIST))
902
reillyi38965732015-11-16 18:27:33903 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
904 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46905 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
906 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44907 problems = [] # items are (filename, line_number, line)
908 for f in input_api.AffectedSourceFiles(FilterFile):
909 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46910 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44911 problems.append((f.LocalPath(), line_num, line))
912
913 if problems:
[email protected]f7051d52013-04-02 18:31:42914 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44915 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58916 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44917 [' %s:%d: %s' % (
918 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03919 else:
920 return []
[email protected]06e6d0ff2012-12-11 01:36:44921
922
[email protected]d2530012013-01-25 16:39:27923def _CheckNoAbbreviationInPngFileName(input_api, output_api):
924 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31925 The native_client_sdk directory is excluded because it has auto-generated PNG
926 files for documentation.
[email protected]d2530012013-01-25 16:39:27927 """
[email protected]d2530012013-01-25 16:39:27928 errors = []
binji0dcdf342014-12-12 18:32:31929 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
930 black_list = (r'^native_client_sdk[\\\/]',)
931 file_filter = lambda f: input_api.FilterSourceFile(
932 f, white_list=white_list, black_list=black_list)
933 for f in input_api.AffectedFiles(include_deletes=False,
934 file_filter=file_filter):
935 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27936
937 results = []
938 if errors:
939 results.append(output_api.PresubmitError(
940 'The name of PNG files should not have abbreviations. \n'
941 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
942 'Contact [email protected] if you have questions.', errors))
943 return results
944
945
[email protected]14a6131c2014-01-08 01:15:41946def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08947 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41948 a set of DEPS entries that we should look up.
949
950 For a directory (rather than a specific filename) we fake a path to
951 a specific filename by adding /DEPS. This is chosen as a file that
952 will seldom or never be subject to per-file include_rules.
953 """
[email protected]2b438d62013-11-14 17:54:14954 # We ignore deps entries on auto-generated directories.
955 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08956
957 # This pattern grabs the path without basename in the first
958 # parentheses, and the basename (if present) in the second. It
959 # relies on the simple heuristic that if there is a basename it will
960 # be a header file ending in ".h".
961 pattern = re.compile(
962 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14963 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08964 for changed_line in changed_lines:
965 m = pattern.match(changed_line)
966 if m:
967 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14968 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41969 if m.group(2):
970 results.add('%s%s' % (path, m.group(2)))
971 else:
972 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08973 return results
974
975
[email protected]e871964c2013-05-13 14:14:55976def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
977 """When a dependency prefixed with + is added to a DEPS file, we
978 want to make sure that the change is reviewed by an OWNER of the
979 target file or directory, to avoid layering violations from being
980 introduced. This check verifies that this happens.
981 """
982 changed_lines = set()
983 for f in input_api.AffectedFiles():
984 filename = input_api.os_path.basename(f.LocalPath())
985 if filename == 'DEPS':
986 changed_lines |= set(line.strip()
987 for line_num, line
988 in f.ChangedContents())
989 if not changed_lines:
990 return []
991
[email protected]14a6131c2014-01-08 01:15:41992 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
993 changed_lines)
[email protected]e871964c2013-05-13 14:14:55994 if not virtual_depended_on_files:
995 return []
996
997 if input_api.is_committing:
998 if input_api.tbr:
999 return [output_api.PresubmitNotifyResult(
1000 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1001 if not input_api.change.issue:
1002 return [output_api.PresubmitError(
1003 "DEPS approval by OWNERS check failed: this change has "
1004 "no Rietveld issue number, so we can't check it for approvals.")]
1005 output = output_api.PresubmitError
1006 else:
1007 output = output_api.PresubmitNotifyResult
1008
1009 owners_db = input_api.owners_db
1010 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1011 input_api,
1012 owners_db.email_regexp,
1013 approval_needed=input_api.is_committing)
1014
1015 owner_email = owner_email or input_api.change.author_email
1016
[email protected]de4f7d22013-05-23 14:27:461017 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511018 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461019 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551020 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1021 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411022
1023 # We strip the /DEPS part that was added by
1024 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1025 # directory.
1026 def StripDeps(path):
1027 start_deps = path.rfind('/DEPS')
1028 if start_deps != -1:
1029 return path[:start_deps]
1030 else:
1031 return path
1032 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551033 for path in missing_files]
1034
1035 if unapproved_dependencies:
1036 output_list = [
[email protected]14a6131c2014-01-08 01:15:411037 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551038 '\n '.join(sorted(unapproved_dependencies)))]
1039 if not input_api.is_committing:
1040 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1041 output_list.append(output(
1042 'Suggested missing target path OWNERS:\n %s' %
1043 '\n '.join(suggested_owners or [])))
1044 return output_list
1045
1046 return []
1047
1048
[email protected]85218562013-11-22 07:41:401049def _CheckSpamLogging(input_api, output_api):
1050 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1051 black_list = (_EXCLUDED_PATHS +
1052 _TEST_CODE_EXCLUDED_PATHS +
1053 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501054 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191055 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481056 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461057 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121058 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1059 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581060 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161061 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031062 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151063 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1064 r"^chromecast[\\\/]",
1065 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311066 r"^components[\\\/]html_viewer[\\\/]"
1067 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461068 # TODO(peter): Remove this exception. https://crbug.com/534537
1069 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1070 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251071 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1072 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111073 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151074 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111075 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521076 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501077 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361078 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311079 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131080 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441081 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021082 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441083 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401084 source_file_filter = lambda x: input_api.FilterSourceFile(
1085 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1086
1087 log_info = []
1088 printf = []
1089
1090 for f in input_api.AffectedSourceFiles(source_file_filter):
1091 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471092 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401093 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471094 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131095 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371096
mohan.reddyf21db962014-10-16 12:26:471097 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371098 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471099 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401100 printf.append(f.LocalPath())
1101
1102 if log_info:
1103 return [output_api.PresubmitError(
1104 'These files spam the console log with LOG(INFO):',
1105 items=log_info)]
1106 if printf:
1107 return [output_api.PresubmitError(
1108 'These files spam the console log with printf/fprintf:',
1109 items=printf)]
1110 return []
1111
1112
[email protected]49aa76a2013-12-04 06:59:161113def _CheckForAnonymousVariables(input_api, output_api):
1114 """These types are all expected to hold locks while in scope and
1115 so should never be anonymous (which causes them to be immediately
1116 destroyed)."""
1117 they_who_must_be_named = [
1118 'base::AutoLock',
1119 'base::AutoReset',
1120 'base::AutoUnlock',
1121 'SkAutoAlphaRestore',
1122 'SkAutoBitmapShaderInstall',
1123 'SkAutoBlitterChoose',
1124 'SkAutoBounderCommit',
1125 'SkAutoCallProc',
1126 'SkAutoCanvasRestore',
1127 'SkAutoCommentBlock',
1128 'SkAutoDescriptor',
1129 'SkAutoDisableDirectionCheck',
1130 'SkAutoDisableOvalCheck',
1131 'SkAutoFree',
1132 'SkAutoGlyphCache',
1133 'SkAutoHDC',
1134 'SkAutoLockColors',
1135 'SkAutoLockPixels',
1136 'SkAutoMalloc',
1137 'SkAutoMaskFreeImage',
1138 'SkAutoMutexAcquire',
1139 'SkAutoPathBoundsUpdate',
1140 'SkAutoPDFRelease',
1141 'SkAutoRasterClipValidate',
1142 'SkAutoRef',
1143 'SkAutoTime',
1144 'SkAutoTrace',
1145 'SkAutoUnref',
1146 ]
1147 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1148 # bad: base::AutoLock(lock.get());
1149 # not bad: base::AutoLock lock(lock.get());
1150 bad_pattern = input_api.re.compile(anonymous)
1151 # good: new base::AutoLock(lock.get())
1152 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1153 errors = []
1154
1155 for f in input_api.AffectedFiles():
1156 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1157 continue
1158 for linenum, line in f.ChangedContents():
1159 if bad_pattern.search(line) and not good_pattern.search(line):
1160 errors.append('%s:%d' % (f.LocalPath(), linenum))
1161
1162 if errors:
1163 return [output_api.PresubmitError(
1164 'These lines create anonymous variables that need to be named:',
1165 items=errors)]
1166 return []
1167
1168
[email protected]5fe0f8742013-11-29 01:04:591169def _CheckCygwinShell(input_api, output_api):
1170 source_file_filter = lambda x: input_api.FilterSourceFile(
1171 x, white_list=(r'.+\.(gyp|gypi)$',))
1172 cygwin_shell = []
1173
1174 for f in input_api.AffectedSourceFiles(source_file_filter):
1175 for linenum, line in f.ChangedContents():
1176 if 'msvs_cygwin_shell' in line:
1177 cygwin_shell.append(f.LocalPath())
1178 break
1179
1180 if cygwin_shell:
1181 return [output_api.PresubmitError(
1182 'These files should not use msvs_cygwin_shell (the default is 0):',
1183 items=cygwin_shell)]
1184 return []
1185
[email protected]85218562013-11-22 07:41:401186
[email protected]999261d2014-03-03 20:08:081187def _CheckUserActionUpdate(input_api, output_api):
1188 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521189 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081190 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521191 # If actions.xml is already included in the changelist, the PRESUBMIT
1192 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081193 return []
1194
[email protected]999261d2014-03-03 20:08:081195 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1196 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521197 current_actions = None
[email protected]999261d2014-03-03 20:08:081198 for f in input_api.AffectedFiles(file_filter=file_filter):
1199 for line_num, line in f.ChangedContents():
1200 match = input_api.re.search(action_re, line)
1201 if match:
[email protected]2f92dec2014-03-07 19:21:521202 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1203 # loaded only once.
1204 if not current_actions:
1205 with open('tools/metrics/actions/actions.xml') as actions_f:
1206 current_actions = actions_f.read()
1207 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081208 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521209 action = 'name="{0}"'.format(action_name)
1210 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081211 return [output_api.PresubmitPromptWarning(
1212 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521213 'tools/metrics/actions/actions.xml. Please run '
1214 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081215 % (f.LocalPath(), line_num, action_name))]
1216 return []
1217
1218
[email protected]99171a92014-06-03 08:44:471219def _GetJSONParseError(input_api, filename, eat_comments=True):
1220 try:
1221 contents = input_api.ReadFile(filename)
1222 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131223 import sys
1224 original_sys_path = sys.path
1225 try:
1226 sys.path = sys.path + [input_api.os_path.join(
1227 input_api.PresubmitLocalPath(),
1228 'tools', 'json_comment_eater')]
1229 import json_comment_eater
1230 finally:
1231 sys.path = original_sys_path
1232 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471233
1234 input_api.json.loads(contents)
1235 except ValueError as e:
1236 return e
1237 return None
1238
1239
1240def _GetIDLParseError(input_api, filename):
1241 try:
1242 contents = input_api.ReadFile(filename)
1243 idl_schema = input_api.os_path.join(
1244 input_api.PresubmitLocalPath(),
1245 'tools', 'json_schema_compiler', 'idl_schema.py')
1246 process = input_api.subprocess.Popen(
1247 [input_api.python_executable, idl_schema],
1248 stdin=input_api.subprocess.PIPE,
1249 stdout=input_api.subprocess.PIPE,
1250 stderr=input_api.subprocess.PIPE,
1251 universal_newlines=True)
1252 (_, error) = process.communicate(input=contents)
1253 return error or None
1254 except ValueError as e:
1255 return e
1256
1257
1258def _CheckParseErrors(input_api, output_api):
1259 """Check that IDL and JSON files do not contain syntax errors."""
1260 actions = {
1261 '.idl': _GetIDLParseError,
1262 '.json': _GetJSONParseError,
1263 }
1264 # These paths contain test data and other known invalid JSON files.
1265 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491266 r'test[\\\/]data[\\\/]',
1267 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471268 ]
1269 # Most JSON files are preprocessed and support comments, but these do not.
1270 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491271 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471272 ]
1273 # Only run IDL checker on files in these directories.
1274 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491275 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1276 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471277 ]
1278
1279 def get_action(affected_file):
1280 filename = affected_file.LocalPath()
1281 return actions.get(input_api.os_path.splitext(filename)[1])
1282
1283 def MatchesFile(patterns, path):
1284 for pattern in patterns:
1285 if input_api.re.search(pattern, path):
1286 return True
1287 return False
1288
1289 def FilterFile(affected_file):
1290 action = get_action(affected_file)
1291 if not action:
1292 return False
1293 path = affected_file.LocalPath()
1294
1295 if MatchesFile(excluded_patterns, path):
1296 return False
1297
1298 if (action == _GetIDLParseError and
1299 not MatchesFile(idl_included_patterns, path)):
1300 return False
1301 return True
1302
1303 results = []
1304 for affected_file in input_api.AffectedFiles(
1305 file_filter=FilterFile, include_deletes=False):
1306 action = get_action(affected_file)
1307 kwargs = {}
1308 if (action == _GetJSONParseError and
1309 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1310 kwargs['eat_comments'] = False
1311 parse_error = action(input_api,
1312 affected_file.AbsoluteLocalPath(),
1313 **kwargs)
1314 if parse_error:
1315 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1316 (affected_file.LocalPath(), parse_error)))
1317 return results
1318
1319
[email protected]760deea2013-12-10 19:33:491320def _CheckJavaStyle(input_api, output_api):
1321 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471322 import sys
[email protected]760deea2013-12-10 19:33:491323 original_sys_path = sys.path
1324 try:
1325 sys.path = sys.path + [input_api.os_path.join(
1326 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1327 import checkstyle
1328 finally:
1329 # Restore sys.path to what it was before.
1330 sys.path = original_sys_path
1331
1332 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091333 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511334 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491335
1336
dskiba88634f4e2015-08-14 23:03:291337def _CheckAndroidToastUsage(input_api, output_api):
1338 """Checks that code uses org.chromium.ui.widget.Toast instead of
1339 android.widget.Toast (Chromium Toast doesn't force hardware
1340 acceleration on low-end devices, saving memory).
1341 """
1342 toast_import_pattern = input_api.re.compile(
1343 r'^import android\.widget\.Toast;$')
1344
1345 errors = []
1346
1347 sources = lambda affected_file: input_api.FilterSourceFile(
1348 affected_file,
1349 black_list=(_EXCLUDED_PATHS +
1350 _TEST_CODE_EXCLUDED_PATHS +
1351 input_api.DEFAULT_BLACK_LIST +
1352 (r'^chromecast[\\\/].*',
1353 r'^remoting[\\\/].*')),
1354 white_list=(r'.*\.java$',))
1355
1356 for f in input_api.AffectedSourceFiles(sources):
1357 for line_num, line in f.ChangedContents():
1358 if toast_import_pattern.search(line):
1359 errors.append("%s:%d" % (f.LocalPath(), line_num))
1360
1361 results = []
1362
1363 if errors:
1364 results.append(output_api.PresubmitError(
1365 'android.widget.Toast usage is detected. Android toasts use hardware'
1366 ' acceleration, and can be\ncostly on low-end devices. Please use'
1367 ' org.chromium.ui.widget.Toast instead.\n'
1368 'Contact [email protected] if you have any questions.',
1369 errors))
1370
1371 return results
1372
1373
dgnaa68d5e2015-06-10 10:08:221374def _CheckAndroidCrLogUsage(input_api, output_api):
1375 """Checks that new logs using org.chromium.base.Log:
1376 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511377 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221378 """
1379 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121380 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1381 class_in_base_pattern = input_api.re.compile(
1382 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1383 has_some_log_import_pattern = input_api.re.compile(
1384 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221385 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121386 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221387 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511388 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221389 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221390
Vincent Scheib16d7b272015-09-15 18:09:071391 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221392 'or contact [email protected] for more info.')
1393 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121394
dgnaa68d5e2015-06-10 10:08:221395 tag_decl_errors = []
1396 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121397 tag_errors = []
dgn38736db2015-09-18 19:20:511398 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121399 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221400
1401 for f in input_api.AffectedSourceFiles(sources):
1402 file_content = input_api.ReadFile(f)
1403 has_modified_logs = False
1404
1405 # Per line checks
dgn87d9fb62015-06-12 09:15:121406 if (cr_log_import_pattern.search(file_content) or
1407 (class_in_base_pattern.search(file_content) and
1408 not has_some_log_import_pattern.search(file_content))):
1409 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221410 for line_num, line in f.ChangedContents():
1411
1412 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121413 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221414 if match:
1415 has_modified_logs = True
1416
1417 # Make sure it uses "TAG"
1418 if not match.group('tag') == 'TAG':
1419 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121420 else:
1421 # Report non cr Log function calls in changed lines
1422 for line_num, line in f.ChangedContents():
1423 if log_call_pattern.search(line):
1424 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221425
1426 # Per file checks
1427 if has_modified_logs:
1428 # Make sure the tag is using the "cr" prefix and is not too long
1429 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511430 tag_name = match.group('name') if match else None
1431 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221432 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511433 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221434 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511435 elif '.' in tag_name:
1436 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221437
1438 results = []
1439 if tag_decl_errors:
1440 results.append(output_api.PresubmitPromptWarning(
1441 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511442 '"private static final String TAG = "<package tag>".\n'
1443 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221444 tag_decl_errors))
1445
1446 if tag_length_errors:
1447 results.append(output_api.PresubmitError(
1448 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511449 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221450 tag_length_errors))
1451
1452 if tag_errors:
1453 results.append(output_api.PresubmitPromptWarning(
1454 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1455 tag_errors))
1456
dgn87d9fb62015-06-12 09:15:121457 if util_log_errors:
dgn4401aa52015-04-29 16:26:171458 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121459 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1460 util_log_errors))
1461
dgn38736db2015-09-18 19:20:511462 if tag_with_dot_errors:
1463 results.append(output_api.PresubmitPromptWarning(
1464 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1465 tag_with_dot_errors))
1466
dgn4401aa52015-04-29 16:26:171467 return results
1468
1469
agrieve7b6479d82015-10-07 14:24:221470def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1471 """Checks if MDPI assets are placed in a correct directory."""
1472 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1473 ('/res/drawable/' in f.LocalPath() or
1474 '/res/drawable-ldrtl/' in f.LocalPath()))
1475 errors = []
1476 for f in input_api.AffectedFiles(include_deletes=False,
1477 file_filter=file_filter):
1478 errors.append(' %s' % f.LocalPath())
1479
1480 results = []
1481 if errors:
1482 results.append(output_api.PresubmitError(
1483 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1484 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1485 '/res/drawable-ldrtl/.\n'
1486 'Contact [email protected] if you have questions.', errors))
1487 return results
1488
1489
mnaganov9b9b1fe82014-12-11 16:30:361490def _CheckForCopyrightedCode(input_api, output_api):
1491 """Verifies that newly added code doesn't contain copyrighted material
1492 and is properly licensed under the standard Chromium license.
1493
1494 As there can be false positives, we maintain a whitelist file. This check
1495 also verifies that the whitelist file is up to date.
1496 """
1497 import sys
1498 original_sys_path = sys.path
1499 try:
1500 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221501 input_api.PresubmitLocalPath(), 'tools')]
1502 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361503 finally:
1504 # Restore sys.path to what it was before.
1505 sys.path = original_sys_path
1506
1507 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1508
1509
glidere61efad2015-02-18 17:39:431510def _CheckSingletonInHeaders(input_api, output_api):
1511 """Checks to make sure no header files have |Singleton<|."""
1512 def FileFilter(affected_file):
1513 # It's ok for base/memory/singleton.h to have |Singleton<|.
1514 black_list = (_EXCLUDED_PATHS +
1515 input_api.DEFAULT_BLACK_LIST +
1516 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1517 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1518
sergeyu34d21222015-09-16 00:11:441519 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431520 files = []
1521 for f in input_api.AffectedSourceFiles(FileFilter):
1522 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1523 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1524 contents = input_api.ReadFile(f)
1525 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241526 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431527 pattern.search(line)):
1528 files.append(f)
1529 break
1530
1531 if files:
1532 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441533 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431534 'Please move them to an appropriate source file so that the ' +
1535 'template gets instantiated in a single compilation unit.',
1536 files) ]
1537 return []
1538
1539
dbeam3aa38392015-10-16 21:38:031540def _CheckBaseMacrosInHeaders(input_api, output_api):
1541 """Check for base/macros.h if DISALLOW_* macro is used."""
1542
1543 disallows = ('DISALLOW_ASSIGN', 'DISALLOW_COPY', 'DISALLOW_EVIL')
1544 macros = '#include "base/macros.h"'
1545 basictypes = '#include "base/basictypes.h"'
1546
1547 files = []
1548 for f in input_api.AffectedSourceFiles(None):
1549 if not f.LocalPath().endswith('.h'):
1550 continue
1551 for line_num, line in f.ChangedContents():
oysteinec430ad42015-10-22 20:55:241552 if line.lstrip().startswith('//'): # Strip C++ comment.
1553 continue
dbeam3aa38392015-10-16 21:38:031554 if any(d in line for d in disallows):
1555 contents = input_api.ReadFile(f)
1556 if not (macros in contents or basictypes in contents):
1557 files.append(f)
1558 break
1559
1560 msg = ('The following files appear to be using DISALLOW_* macros.\n'
1561 'Please #include "base/macros.h" in them.')
1562 return [output_api.PresubmitError(msg, files)] if files else []
1563
1564
[email protected]fd20b902014-05-09 02:14:531565_DEPRECATED_CSS = [
1566 # Values
1567 ( "-webkit-box", "flex" ),
1568 ( "-webkit-inline-box", "inline-flex" ),
1569 ( "-webkit-flex", "flex" ),
1570 ( "-webkit-inline-flex", "inline-flex" ),
1571 ( "-webkit-min-content", "min-content" ),
1572 ( "-webkit-max-content", "max-content" ),
1573
1574 # Properties
1575 ( "-webkit-background-clip", "background-clip" ),
1576 ( "-webkit-background-origin", "background-origin" ),
1577 ( "-webkit-background-size", "background-size" ),
1578 ( "-webkit-box-shadow", "box-shadow" ),
1579
1580 # Functions
1581 ( "-webkit-gradient", "gradient" ),
1582 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1583 ( "-webkit-linear-gradient", "linear-gradient" ),
1584 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1585 ( "-webkit-radial-gradient", "radial-gradient" ),
1586 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1587]
1588
1589def _CheckNoDeprecatedCSS(input_api, output_api):
1590 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251591 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341592 documentation and iOS CSS for dom distiller
1593 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251594 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531595 results = []
dbeam070cfe62014-10-22 06:44:021596 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251597 black_list = (_EXCLUDED_PATHS +
1598 _TEST_CODE_EXCLUDED_PATHS +
1599 input_api.DEFAULT_BLACK_LIST +
1600 (r"^chrome/common/extensions/docs",
1601 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341602 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051603 r"^components/flags_ui/resources/apple_flags.css",
[email protected]9a48e3f82014-05-22 00:06:251604 r"^native_client_sdk"))
1605 file_filter = lambda f: input_api.FilterSourceFile(
1606 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531607 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1608 for line_num, line in fpath.ChangedContents():
1609 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021610 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531611 results.append(output_api.PresubmitError(
1612 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1613 (fpath.LocalPath(), line_num, deprecated_value, value)))
1614 return results
1615
mohan.reddyf21db962014-10-16 12:26:471616
dbeam070cfe62014-10-22 06:44:021617_DEPRECATED_JS = [
1618 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1619 ( "__defineGetter__", "Object.defineProperty" ),
1620 ( "__defineSetter__", "Object.defineProperty" ),
1621]
1622
1623def _CheckNoDeprecatedJS(input_api, output_api):
1624 """Make sure that we don't use deprecated JS in Chrome code."""
1625 results = []
1626 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1627 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1628 input_api.DEFAULT_BLACK_LIST)
1629 file_filter = lambda f: input_api.FilterSourceFile(
1630 f, white_list=file_inclusion_pattern, black_list=black_list)
1631 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1632 for lnum, line in fpath.ChangedContents():
1633 for (deprecated, replacement) in _DEPRECATED_JS:
1634 if deprecated in line:
1635 results.append(output_api.PresubmitError(
1636 "%s:%d: Use of deprecated JS %s, use %s instead" %
1637 (fpath.LocalPath(), lnum, deprecated, replacement)))
1638 return results
1639
1640
dgnaa68d5e2015-06-10 10:08:221641def _AndroidSpecificOnUploadChecks(input_api, output_api):
1642 """Groups checks that target android code."""
1643 results = []
dgnaa68d5e2015-06-10 10:08:221644 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221645 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291646 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221647 return results
1648
1649
[email protected]22c9bd72011-03-27 16:47:391650def _CommonChecks(input_api, output_api):
1651 """Checks common to both upload and commit."""
1652 results = []
1653 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381654 input_api, output_api,
1655 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461656 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191657 results.extend(
[email protected]760deea2013-12-10 19:33:491658 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541659 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181660 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521661 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221662 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441663 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591664 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061665 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121666 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181667 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221668 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491669 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271670 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031671 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491672 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441673 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271674 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541675 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441676 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461677 # TODO(danakj): Remove this when base/move.h is removed.
1678 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551679 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041680 results.extend(
1681 input_api.canned_checks.CheckChangeHasNoTabs(
1682 input_api,
1683 output_api,
1684 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401685 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161686 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591687 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081688 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531689 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021690 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471691 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041692 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361693 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231694 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431695 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam3aa38392015-10-16 21:38:031696 results.extend(_CheckBaseMacrosInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241697
1698 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1699 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1700 input_api, output_api,
1701 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381702 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391703 return results
[email protected]1f7b4172010-01-28 01:17:341704
[email protected]b337cb5b2011-01-23 21:24:051705
[email protected]66daa702011-05-28 14:41:461706def _CheckAuthorizedAuthor(input_api, output_api):
1707 """For non-googler/chromites committers, verify the author's email address is
1708 in AUTHORS.
1709 """
[email protected]9bb9cb82011-06-13 20:43:011710 # TODO(maruel): Add it to input_api?
1711 import fnmatch
1712
[email protected]66daa702011-05-28 14:41:461713 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011714 if not author:
1715 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461716 return []
[email protected]c99663292011-05-31 19:46:081717 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461718 input_api.PresubmitLocalPath(), 'AUTHORS')
1719 valid_authors = (
1720 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1721 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181722 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441723 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231724 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461725 return [output_api.PresubmitPromptWarning(
1726 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1727 '\n'
1728 'http://www.chromium.org/developers/contributing-code and read the '
1729 '"Legal" section\n'
1730 'If you are a chromite, verify the contributor signed the CLA.') %
1731 author)]
1732 return []
1733
1734
[email protected]b8079ae4a2012-12-05 19:56:491735def _CheckPatchFiles(input_api, output_api):
1736 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1737 if f.LocalPath().endswith(('.orig', '.rej'))]
1738 if problems:
1739 return [output_api.PresubmitError(
1740 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031741 else:
1742 return []
[email protected]b8079ae4a2012-12-05 19:56:491743
1744
[email protected]b00342e7f2013-03-26 16:21:541745def _DidYouMeanOSMacro(bad_macro):
1746 try:
1747 return {'A': 'OS_ANDROID',
1748 'B': 'OS_BSD',
1749 'C': 'OS_CHROMEOS',
1750 'F': 'OS_FREEBSD',
1751 'L': 'OS_LINUX',
1752 'M': 'OS_MACOSX',
1753 'N': 'OS_NACL',
1754 'O': 'OS_OPENBSD',
1755 'P': 'OS_POSIX',
1756 'S': 'OS_SOLARIS',
1757 'W': 'OS_WIN'}[bad_macro[3].upper()]
1758 except KeyError:
1759 return ''
1760
1761
1762def _CheckForInvalidOSMacrosInFile(input_api, f):
1763 """Check for sensible looking, totally invalid OS macros."""
1764 preprocessor_statement = input_api.re.compile(r'^\s*#')
1765 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1766 results = []
1767 for lnum, line in f.ChangedContents():
1768 if preprocessor_statement.search(line):
1769 for match in os_macro.finditer(line):
1770 if not match.group(1) in _VALID_OS_MACROS:
1771 good = _DidYouMeanOSMacro(match.group(1))
1772 did_you_mean = ' (did you mean %s?)' % good if good else ''
1773 results.append(' %s:%d %s%s' % (f.LocalPath(),
1774 lnum,
1775 match.group(1),
1776 did_you_mean))
1777 return results
1778
1779
1780def _CheckForInvalidOSMacros(input_api, output_api):
1781 """Check all affected files for invalid OS macros."""
1782 bad_macros = []
1783 for f in input_api.AffectedFiles():
1784 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1785 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1786
1787 if not bad_macros:
1788 return []
1789
1790 return [output_api.PresubmitError(
1791 'Possibly invalid OS macro[s] found. Please fix your code\n'
1792 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1793
lliabraa35bab3932014-10-01 12:16:441794
1795def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1796 """Check all affected files for invalid "if defined" macros."""
1797 ALWAYS_DEFINED_MACROS = (
1798 "TARGET_CPU_PPC",
1799 "TARGET_CPU_PPC64",
1800 "TARGET_CPU_68K",
1801 "TARGET_CPU_X86",
1802 "TARGET_CPU_ARM",
1803 "TARGET_CPU_MIPS",
1804 "TARGET_CPU_SPARC",
1805 "TARGET_CPU_ALPHA",
1806 "TARGET_IPHONE_SIMULATOR",
1807 "TARGET_OS_EMBEDDED",
1808 "TARGET_OS_IPHONE",
1809 "TARGET_OS_MAC",
1810 "TARGET_OS_UNIX",
1811 "TARGET_OS_WIN32",
1812 )
1813 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1814 results = []
1815 for lnum, line in f.ChangedContents():
1816 for match in ifdef_macro.finditer(line):
1817 if match.group(1) in ALWAYS_DEFINED_MACROS:
1818 always_defined = ' %s is always defined. ' % match.group(1)
1819 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1820 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1821 lnum,
1822 always_defined,
1823 did_you_mean))
1824 return results
1825
1826
1827def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1828 """Check all affected files for invalid "if defined" macros."""
1829 bad_macros = []
1830 for f in input_api.AffectedFiles():
1831 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1832 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1833
1834 if not bad_macros:
1835 return []
1836
1837 return [output_api.PresubmitError(
1838 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1839 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1840 bad_macros)]
1841
1842
danakj3c84d0c2014-10-06 15:35:461843def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1844 """Check all affected files for using side effects of Pass."""
1845 errors = []
1846 for f in input_api.AffectedFiles():
1847 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1848 for lnum, line in f.ChangedContents():
1849 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471850 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461851 errors.append(output_api.PresubmitError(
1852 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1853 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1854 return errors
1855
1856
mlamouria82272622014-09-16 18:45:041857def _CheckForIPCRules(input_api, output_api):
1858 """Check for same IPC rules described in
1859 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1860 """
1861 base_pattern = r'IPC_ENUM_TRAITS\('
1862 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1863 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1864
1865 problems = []
1866 for f in input_api.AffectedSourceFiles(None):
1867 local_path = f.LocalPath()
1868 if not local_path.endswith('.h'):
1869 continue
1870 for line_number, line in f.ChangedContents():
1871 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1872 problems.append(
1873 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1874
1875 if problems:
1876 return [output_api.PresubmitPromptWarning(
1877 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1878 else:
1879 return []
1880
[email protected]b00342e7f2013-03-26 16:21:541881
mostynbb639aca52015-01-07 20:31:231882def _CheckForWindowsLineEndings(input_api, output_api):
1883 """Check source code and known ascii text files for Windows style line
1884 endings.
1885 """
earthdok1b5e0ee2015-03-10 15:19:101886 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231887
1888 file_inclusion_pattern = (
1889 known_text_files,
1890 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1891 )
1892
1893 filter = lambda f: input_api.FilterSourceFile(
1894 f, white_list=file_inclusion_pattern, black_list=None)
1895 files = [f.LocalPath() for f in
1896 input_api.AffectedSourceFiles(filter)]
1897
1898 problems = []
1899
1900 for file in files:
1901 fp = open(file, 'r')
1902 for line in fp:
1903 if line.endswith('\r\n'):
1904 problems.append(file)
1905 break
1906 fp.close()
1907
1908 if problems:
1909 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1910 'these files to contain Windows style line endings?\n' +
1911 '\n'.join(problems))]
1912
1913 return []
1914
1915
[email protected]1f7b4172010-01-28 01:17:341916def CheckChangeOnUpload(input_api, output_api):
1917 results = []
1918 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471919 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171920 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281921 results.extend(
1922 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191923 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221924 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541925 return results
[email protected]ca8d19842009-02-19 16:33:121926
1927
[email protected]1bfb8322014-04-23 01:02:411928def GetTryServerMasterForBot(bot):
1929 """Returns the Try Server master for the given bot.
1930
[email protected]0bb112362014-07-26 04:38:321931 It tries to guess the master from the bot name, but may still fail
1932 and return None. There is no longer a default master.
1933 """
1934 # Potentially ambiguous bot names are listed explicitly.
1935 master_map = {
[email protected]0bb112362014-07-26 04:38:321936 'chromium_presubmit': 'tryserver.chromium.linux',
1937 'blink_presubmit': 'tryserver.chromium.linux',
1938 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411939 }
[email protected]0bb112362014-07-26 04:38:321940 master = master_map.get(bot)
1941 if not master:
sergiyb37fd293f2015-02-26 06:55:011942 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321943 master = 'tryserver.chromium.linux'
1944 elif 'win' in bot:
1945 master = 'tryserver.chromium.win'
1946 elif 'mac' in bot or 'ios' in bot:
1947 master = 'tryserver.chromium.mac'
1948 return master
[email protected]1bfb8322014-04-23 01:02:411949
1950
Paweł Hajdan, Jr55083782014-12-19 20:32:561951def GetDefaultTryConfigs(bots):
1952 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011953 """
1954
Paweł Hajdan, Jr55083782014-12-19 20:32:561955 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411956
1957 # Build up the mapping from tryserver master to bot/test.
1958 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561959 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411960 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1961 return out
[email protected]38c6a512013-12-18 23:48:011962
1963
[email protected]ca8d19842009-02-19 16:33:121964def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541965 results = []
[email protected]1f7b4172010-01-28 01:17:341966 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541967 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271968 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341969 input_api,
1970 output_api,
[email protected]2fdd1f362013-01-16 03:56:031971 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271972
[email protected]3e4eb112011-01-18 03:29:541973 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1974 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411975 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1976 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541977 return results
[email protected]ca8d19842009-02-19 16:33:121978
1979
[email protected]7468ac522014-03-12 23:35:571980def GetPreferredTryMasters(project, change):
Paweł Hajdan, Jref2afd42015-01-07 15:59:521981 import json
sergiyb57a71e32015-06-03 18:44:001982 import os.path
1983 import platform
1984 import subprocess
smut3ef206e12015-03-20 09:30:001985
sergiyb57a71e32015-06-03 18:44:001986 cq_config_path = os.path.join(
1987 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
1988 # commit_queue.py below is a script in depot_tools directory, which has a
1989 # 'builders' command to retrieve a list of CQ builders from the CQ config.
1990 is_win = platform.system() == 'Windows'
1991 masters = json.loads(subprocess.check_output(
1992 ['commit_queue', 'builders', cq_config_path], shell=is_win))
[email protected]911753b2012-08-02 12:11:541993
sergiyb6092f742015-06-16 09:00:521994 try_config = {}
1995 for master in masters:
1996 try_config.setdefault(master, {})
1997 for builder in masters[master]:
sergiyb57a71e32015-06-03 18:44:001998 # Do not trigger presubmit builders, since they're likely to fail
1999 # (e.g. OWNERS checks before finished code review), and we're
2000 # running local presubmit anyway.
sergiyb6092f742015-06-16 09:00:522001 if 'presubmit' not in builder:
2002 try_config[master][builder] = ['defaulttests']
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:322003
sergiyb6092f742015-06-16 09:00:522004 return try_config