blob: 9a7f4c34b89b7e891432aa639308e3df5b8685c8 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-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]ca8d1982009-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]ca8d1982009-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]ca8d1982009-02-19 16:33:1257
[email protected]eea609a2011-11-18 13:10:1258_TEST_ONLY_WARNING = (
59 'You might be calling functions intended only for testing from\n'
60 'production code. It is OK to ignore this warning if you know what\n'
61 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5862 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1263
64
[email protected]cf9b78f2012-11-14 11:40:2865_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4066 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2167 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
68 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2869
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
143)
144
145
146_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20147 # Make sure that gtest's FRIEND_TEST() macro is not used; the
148 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30149 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20150 (
151 'FRIEND_TEST(',
152 (
[email protected]e3c945502012-06-26 20:01:49153 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20154 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
155 ),
156 False,
[email protected]7345da02012-11-27 14:31:49157 (),
[email protected]23e6cbc2012-06-16 18:51:20158 ),
159 (
160 'ScopedAllowIO',
161 (
[email protected]e3c945502012-06-26 20:01:49162 'New code should not use ScopedAllowIO. Post a task to the blocking',
163 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20164 ),
[email protected]e3c945502012-06-26 20:01:49165 True,
[email protected]7345da02012-11-27 14:31:49166 (
nyad2c548b2015-12-09 03:22:32167 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10168 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22169 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
alematee4016bb2014-11-12 17:38:51170 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
171 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09172 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
[email protected]de7d61ff2013-08-20 11:30:41173 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
174 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48175 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
176 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01177 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54178 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu34d21222015-09-16 00:11:44179 r"^remoting[\\\/]host[\\\/]gnubby_auth_handler_posix\.cc$",
dnicoara171d8c82015-03-05 20:46:18180 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
dnicoarab29d0512015-05-07 19:29:23181 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49182 ),
[email protected]23e6cbc2012-06-16 18:51:20183 ),
[email protected]52657f62013-05-20 05:30:31184 (
185 'SkRefPtr',
186 (
187 'The use of SkRefPtr is prohibited. ',
188 'Please use skia::RefPtr instead.'
189 ),
190 True,
191 (),
192 ),
193 (
194 'SkAutoRef',
195 (
196 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
197 'Please use skia::RefPtr instead.'
198 ),
199 True,
200 (),
201 ),
202 (
203 'SkAutoTUnref',
204 (
205 'The use of SkAutoTUnref is dangerous because it implicitly ',
206 'converts to a raw pointer. Please use skia::RefPtr instead.'
207 ),
208 True,
209 (),
210 ),
211 (
212 'SkAutoUnref',
213 (
214 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
215 'because it implicitly converts to a raw pointer. ',
216 'Please use skia::RefPtr instead.'
217 ),
218 True,
219 (),
220 ),
[email protected]d89eec82013-12-03 14:10:59221 (
222 r'/HANDLE_EINTR\(.*close',
223 (
224 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
225 'descriptor will be closed, and it is incorrect to retry the close.',
226 'Either call close directly and ignore its return value, or wrap close',
227 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
228 ),
229 True,
230 (),
231 ),
232 (
233 r'/IGNORE_EINTR\((?!.*close)',
234 (
235 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
236 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
237 ),
238 True,
239 (
240 # Files that #define IGNORE_EINTR.
241 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
242 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
243 ),
244 ),
[email protected]ec5b3f02014-04-04 18:43:43245 (
246 r'/v8::Extension\(',
247 (
248 'Do not introduce new v8::Extensions into the code base, use',
249 'gin::Wrappable instead. See http://crbug.com/334679',
250 ),
251 True,
[email protected]f55c90ee62014-04-12 00:50:03252 (
joaodasilva718f87672014-08-30 09:25:49253 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03254 ),
[email protected]ec5b3f02014-04-04 18:43:43255 ),
skyostilf9469f72015-04-20 10:38:52256 (
sdefresneeaeccc52015-04-22 08:18:32257 '\<MessageLoopProxy\>',
skyostilf9469f72015-04-20 10:38:52258 (
259 'MessageLoopProxy is deprecated. ',
260 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
261 ),
262 True,
kinuko59024ce2015-04-21 22:18:30263 (
264 # Internal message_loop related code may still use it.
265 r'^base[\\\/]message_loop[\\\/].*',
266 ),
skyostilf9469f72015-04-20 10:38:52267 ),
[email protected]127f18ec2012-06-16 05:05:59268)
269
mlamouria82272622014-09-16 18:45:04270_IPC_ENUM_TRAITS_DEPRECATED = (
271 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
272 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
273
[email protected]127f18ec2012-06-16 05:05:59274
[email protected]b00342e7f2013-03-26 16:21:54275_VALID_OS_MACROS = (
276 # Please keep sorted.
277 'OS_ANDROID',
278 'OS_BSD',
279 'OS_CAT', # For testing.
280 'OS_CHROMEOS',
281 'OS_FREEBSD',
282 'OS_IOS',
283 'OS_LINUX',
284 'OS_MACOSX',
285 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21286 'OS_NACL_NONSFI',
287 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54288 'OS_OPENBSD',
289 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37290 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54291 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54292 'OS_WIN',
293)
294
295
[email protected]55459852011-08-10 15:17:19296def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
297 """Attempts to prevent use of functions intended only for testing in
298 non-testing code. For now this is just a best-effort implementation
299 that ignores header files and may have some false positives. A
300 better implementation would probably need a proper C++ parser.
301 """
302 # We only scan .cc files and the like, as the declaration of
303 # for-testing functions in header files are hard to distinguish from
304 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44305 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19306
jochenc0d4808c2015-07-27 09:25:42307 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19308 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09309 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19310 exclusion_pattern = input_api.re.compile(
311 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
312 base_function_pattern, base_function_pattern))
313
314 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44315 black_list = (_EXCLUDED_PATHS +
316 _TEST_CODE_EXCLUDED_PATHS +
317 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19318 return input_api.FilterSourceFile(
319 affected_file,
320 white_list=(file_inclusion_pattern, ),
321 black_list=black_list)
322
323 problems = []
324 for f in input_api.AffectedSourceFiles(FilterFile):
325 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24326 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03327 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46328 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03329 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19330 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03331 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19332
333 if problems:
[email protected]f7051d52013-04-02 18:31:42334 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03335 else:
336 return []
[email protected]55459852011-08-10 15:17:19337
338
[email protected]10689ca2011-09-02 02:31:54339def _CheckNoIOStreamInHeaders(input_api, output_api):
340 """Checks to make sure no .h files include <iostream>."""
341 files = []
342 pattern = input_api.re.compile(r'^#include\s*<iostream>',
343 input_api.re.MULTILINE)
344 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
345 if not f.LocalPath().endswith('.h'):
346 continue
347 contents = input_api.ReadFile(f)
348 if pattern.search(contents):
349 files.append(f)
350
351 if len(files):
352 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06353 'Do not #include <iostream> in header files, since it inserts static '
354 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54355 '#include <ostream>. See http://crbug.com/94794',
356 files) ]
357 return []
358
359
[email protected]72df4e782012-06-21 16:28:18360def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52361 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18362 problems = []
363 for f in input_api.AffectedFiles():
364 if (not f.LocalPath().endswith(('.cc', '.mm'))):
365 continue
366
367 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04368 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18369 problems.append(' %s:%d' % (f.LocalPath(), line_num))
370
371 if not problems:
372 return []
373 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
374 '\n'.join(problems))]
375
376
danakj61c1aa22015-10-26 19:55:52377def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
378 """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
379 errors = []
380 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
381 input_api.re.MULTILINE)
382 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
383 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
384 continue
385 for lnum, line in f.ChangedContents():
386 if input_api.re.search(pattern, line):
387 errors.append(output_api.PresubmitError(
388 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
389 'DCHECK_IS_ON()", not forgetting the braces.')
390 % (f.LocalPath(), lnum)))
391 return errors
392
393
mcasasb7440c282015-02-04 14:52:19394def _FindHistogramNameInLine(histogram_name, line):
395 """Tries to find a histogram name or prefix in a line."""
396 if not "affected-histogram" in line:
397 return histogram_name in line
398 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
399 # the histogram_name.
400 if not '"' in line:
401 return False
402 histogram_prefix = line.split('\"')[1]
403 return histogram_prefix in histogram_name
404
405
406def _CheckUmaHistogramChanges(input_api, output_api):
407 """Check that UMA histogram names in touched lines can still be found in other
408 lines of the patch or in histograms.xml. Note that this check would not catch
409 the reverse: changes in histograms.xml not matched in the code itself."""
410 touched_histograms = []
411 histograms_xml_modifications = []
412 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
413 for f in input_api.AffectedFiles():
414 # If histograms.xml itself is modified, keep the modified lines for later.
415 if f.LocalPath().endswith(('histograms.xml')):
416 histograms_xml_modifications = f.ChangedContents()
417 continue
418 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
419 continue
420 for line_num, line in f.ChangedContents():
421 found = pattern.search(line)
422 if found:
423 touched_histograms.append([found.group(1), f, line_num])
424
425 # Search for the touched histogram names in the local modifications to
426 # histograms.xml, and, if not found, on the base histograms.xml file.
427 unmatched_histograms = []
428 for histogram_info in touched_histograms:
429 histogram_name_found = False
430 for line_num, line in histograms_xml_modifications:
431 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
432 if histogram_name_found:
433 break
434 if not histogram_name_found:
435 unmatched_histograms.append(histogram_info)
436
eromanb90c82e7e32015-04-01 15:13:49437 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19438 problems = []
439 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49440 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19441 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45442 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19443 histogram_name_found = False
444 for line in histograms_xml:
445 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
446 if histogram_name_found:
447 break
448 if not histogram_name_found:
449 problems.append(' [%s:%d] %s' %
450 (f.LocalPath(), line_num, histogram_name))
451
452 if not problems:
453 return []
454 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
455 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49456 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19457
458
[email protected]8ea5d4b2011-09-13 21:49:22459def _CheckNoNewWStrings(input_api, output_api):
460 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27461 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22462 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20463 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57464 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
465 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20466 continue
[email protected]8ea5d4b2011-09-13 21:49:22467
[email protected]a11dbe9b2012-08-07 01:32:58468 allowWString = False
[email protected]b5c24292011-11-28 14:38:20469 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58470 if 'presubmit: allow wstring' in line:
471 allowWString = True
472 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27473 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58474 allowWString = False
475 else:
476 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22477
[email protected]55463aa62011-10-12 00:48:27478 if not problems:
479 return []
480 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58481 ' If you are calling a cross-platform API that accepts a wstring, '
482 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27483 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22484
485
[email protected]2a8ac9c2011-10-19 17:20:44486def _CheckNoDEPSGIT(input_api, output_api):
487 """Make sure .DEPS.git is never modified manually."""
488 if any(f.LocalPath().endswith('.DEPS.git') for f in
489 input_api.AffectedFiles()):
490 return [output_api.PresubmitError(
491 'Never commit changes to .DEPS.git. This file is maintained by an\n'
492 'automated system based on what\'s in DEPS and your changes will be\n'
493 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34494 '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:44495 'for more information')]
496 return []
497
498
tandriief664692014-09-23 14:51:47499def _CheckValidHostsInDEPS(input_api, output_api):
500 """Checks that DEPS file deps are from allowed_hosts."""
501 # Run only if DEPS file has been modified to annoy fewer bystanders.
502 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
503 return []
504 # Outsource work to gclient verify
505 try:
506 input_api.subprocess.check_output(['gclient', 'verify'])
507 return []
508 except input_api.subprocess.CalledProcessError, error:
509 return [output_api.PresubmitError(
510 'DEPS file must have only git dependencies.',
511 long_text=error.output)]
512
513
[email protected]127f18ec2012-06-16 05:05:59514def _CheckNoBannedFunctions(input_api, output_api):
515 """Make sure that banned functions are not used."""
516 warnings = []
517 errors = []
518
519 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
520 for f in input_api.AffectedFiles(file_filter=file_filter):
521 for line_num, line in f.ChangedContents():
522 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26523 matched = False
524 if func_name[0:1] == '/':
525 regex = func_name[1:]
526 if input_api.re.search(regex, line):
527 matched = True
528 elif func_name in line:
529 matched = True
530 if matched:
[email protected]127f18ec2012-06-16 05:05:59531 problems = warnings;
532 if error:
533 problems = errors;
534 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
535 for message_line in message:
536 problems.append(' %s' % message_line)
537
538 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
539 for f in input_api.AffectedFiles(file_filter=file_filter):
540 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49541 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
542 def IsBlacklisted(affected_file, blacklist):
543 local_path = affected_file.LocalPath()
544 for item in blacklist:
545 if input_api.re.match(item, local_path):
546 return True
547 return False
548 if IsBlacklisted(f, excluded_paths):
549 continue
[email protected]d89eec82013-12-03 14:10:59550 matched = False
551 if func_name[0:1] == '/':
552 regex = func_name[1:]
553 if input_api.re.search(regex, line):
554 matched = True
555 elif func_name in line:
556 matched = True
557 if matched:
[email protected]127f18ec2012-06-16 05:05:59558 problems = warnings;
559 if error:
560 problems = errors;
561 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
562 for message_line in message:
563 problems.append(' %s' % message_line)
564
565 result = []
566 if (warnings):
567 result.append(output_api.PresubmitPromptWarning(
568 'Banned functions were used.\n' + '\n'.join(warnings)))
569 if (errors):
570 result.append(output_api.PresubmitError(
571 'Banned functions were used.\n' + '\n'.join(errors)))
572 return result
573
574
[email protected]6c063c62012-07-11 19:11:06575def _CheckNoPragmaOnce(input_api, output_api):
576 """Make sure that banned functions are not used."""
577 files = []
578 pattern = input_api.re.compile(r'^#pragma\s+once',
579 input_api.re.MULTILINE)
580 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
581 if not f.LocalPath().endswith('.h'):
582 continue
583 contents = input_api.ReadFile(f)
584 if pattern.search(contents):
585 files.append(f)
586
587 if files:
588 return [output_api.PresubmitError(
589 'Do not use #pragma once in header files.\n'
590 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
591 files)]
592 return []
593
[email protected]127f18ec2012-06-16 05:05:59594
[email protected]e7479052012-09-19 00:26:12595def _CheckNoTrinaryTrueFalse(input_api, output_api):
596 """Checks to make sure we don't introduce use of foo ? true : false."""
597 problems = []
598 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
599 for f in input_api.AffectedFiles():
600 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
601 continue
602
603 for line_num, line in f.ChangedContents():
604 if pattern.match(line):
605 problems.append(' %s:%d' % (f.LocalPath(), line_num))
606
607 if not problems:
608 return []
609 return [output_api.PresubmitPromptWarning(
610 'Please consider avoiding the "? true : false" pattern if possible.\n' +
611 '\n'.join(problems))]
612
613
[email protected]55f9f382012-07-31 11:02:18614def _CheckUnwantedDependencies(input_api, output_api):
615 """Runs checkdeps on #include statements added in this
616 change. Breaking - rules is an error, breaking ! rules is a
617 warning.
618 """
mohan.reddyf21db962014-10-16 12:26:47619 import sys
[email protected]55f9f382012-07-31 11:02:18620 # We need to wait until we have an input_api object and use this
621 # roundabout construct to import checkdeps because this file is
622 # eval-ed and thus doesn't have __file__.
623 original_sys_path = sys.path
624 try:
625 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47626 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18627 import checkdeps
628 from cpp_checker import CppChecker
629 from rules import Rule
630 finally:
631 # Restore sys.path to what it was before.
632 sys.path = original_sys_path
633
634 added_includes = []
635 for f in input_api.AffectedFiles():
636 if not CppChecker.IsCppFile(f.LocalPath()):
637 continue
638
639 changed_lines = [line for line_num, line in f.ChangedContents()]
640 added_includes.append([f.LocalPath(), changed_lines])
641
[email protected]26385172013-05-09 23:11:35642 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18643
644 error_descriptions = []
645 warning_descriptions = []
646 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
647 added_includes):
648 description_with_path = '%s\n %s' % (path, rule_description)
649 if rule_type == Rule.DISALLOW:
650 error_descriptions.append(description_with_path)
651 else:
652 warning_descriptions.append(description_with_path)
653
654 results = []
655 if error_descriptions:
656 results.append(output_api.PresubmitError(
657 'You added one or more #includes that violate checkdeps rules.',
658 error_descriptions))
659 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42660 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18661 'You added one or more #includes of files that are temporarily\n'
662 'allowed but being removed. Can you avoid introducing the\n'
663 '#include? See relevant DEPS file(s) for details and contacts.',
664 warning_descriptions))
665 return results
666
667
[email protected]fbcafe5a2012-08-08 15:31:22668def _CheckFilePermissions(input_api, output_api):
669 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15670 if input_api.platform == 'win32':
671 return []
mohan.reddyf21db962014-10-16 12:26:47672 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
673 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22674 for f in input_api.AffectedFiles():
675 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11676 try:
677 input_api.subprocess.check_output(args)
678 return []
679 except input_api.subprocess.CalledProcessError as error:
680 return [output_api.PresubmitError(
681 'checkperms.py failed:',
682 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22683
684
[email protected]c8278b32012-10-30 20:35:49685def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
686 """Makes sure we don't include ui/aura/window_property.h
687 in header files.
688 """
689 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
690 errors = []
691 for f in input_api.AffectedFiles():
692 if not f.LocalPath().endswith('.h'):
693 continue
694 for line_num, line in f.ChangedContents():
695 if pattern.match(line):
696 errors.append(' %s:%d' % (f.LocalPath(), line_num))
697
698 results = []
699 if errors:
700 results.append(output_api.PresubmitError(
701 'Header files should not include ui/aura/window_property.h', errors))
702 return results
703
704
[email protected]cf9b78f2012-11-14 11:40:28705def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
706 """Checks that the lines in scope occur in the right order.
707
708 1. C system files in alphabetical order
709 2. C++ system files in alphabetical order
710 3. Project's .h files
711 """
712
713 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
714 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
715 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
716
717 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
718
719 state = C_SYSTEM_INCLUDES
720
721 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57722 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28723 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55724 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28725 for line_num, line in scope:
726 if c_system_include_pattern.match(line):
727 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55728 problem_linenums.append((line_num, previous_line_num,
729 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28730 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55731 problem_linenums.append((line_num, previous_line_num,
732 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28733 elif cpp_system_include_pattern.match(line):
734 if state == C_SYSTEM_INCLUDES:
735 state = CPP_SYSTEM_INCLUDES
736 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55737 problem_linenums.append((line_num, previous_line_num,
738 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28739 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55740 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28741 elif custom_include_pattern.match(line):
742 if state != CUSTOM_INCLUDES:
743 state = CUSTOM_INCLUDES
744 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55745 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28746 else:
brucedawson70fadb02015-06-30 17:47:55747 problem_linenums.append((line_num, previous_line_num,
748 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28749 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57750 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28751
752 warnings = []
brucedawson70fadb02015-06-30 17:47:55753 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57754 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55755 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28756 return warnings
757
758
[email protected]ac294a12012-12-06 16:38:43759def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28760 """Checks the #include order for the given file f."""
761
[email protected]2299dcf2012-11-15 19:56:24762 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30763 # Exclude the following includes from the check:
764 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
765 # specific order.
766 # 2) <atlbase.h>, "build/build_config.h"
767 excluded_include_pattern = input_api.re.compile(
768 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24769 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33770 # Match the final or penultimate token if it is xxxtest so we can ignore it
771 # when considering the special first include.
772 test_file_tag_pattern = input_api.re.compile(
773 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11774 if_pattern = input_api.re.compile(
775 r'\s*#\s*(if|elif|else|endif|define|undef).*')
776 # Some files need specialized order of includes; exclude such files from this
777 # check.
778 uncheckable_includes_pattern = input_api.re.compile(
779 r'\s*#include '
780 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28781
782 contents = f.NewContents()
783 warnings = []
784 line_num = 0
785
[email protected]ac294a12012-12-06 16:38:43786 # Handle the special first include. If the first include file is
787 # some/path/file.h, the corresponding including file can be some/path/file.cc,
788 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
789 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33790 # If the included file is some/path/file_platform.h the including file could
791 # also be some/path/file_xxxtest_platform.h.
792 including_file_base_name = test_file_tag_pattern.sub(
793 '', input_api.os_path.basename(f.LocalPath()))
794
[email protected]ac294a12012-12-06 16:38:43795 for line in contents:
796 line_num += 1
797 if system_include_pattern.match(line):
798 # No special first include -> process the line again along with normal
799 # includes.
800 line_num -= 1
801 break
802 match = custom_include_pattern.match(line)
803 if match:
804 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33805 header_basename = test_file_tag_pattern.sub(
806 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
807
808 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24809 # No special first include -> process the line again along with normal
810 # includes.
811 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43812 break
[email protected]cf9b78f2012-11-14 11:40:28813
814 # Split into scopes: Each region between #if and #endif is its own scope.
815 scopes = []
816 current_scope = []
817 for line in contents[line_num:]:
818 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11819 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54820 continue
[email protected]2309b0fa02012-11-16 12:18:27821 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28822 scopes.append(current_scope)
823 current_scope = []
[email protected]962f117e2012-11-22 18:11:56824 elif ((system_include_pattern.match(line) or
825 custom_include_pattern.match(line)) and
826 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28827 current_scope.append((line_num, line))
828 scopes.append(current_scope)
829
830 for scope in scopes:
831 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
832 changed_linenums))
833 return warnings
834
835
836def _CheckIncludeOrder(input_api, output_api):
837 """Checks that the #include order is correct.
838
839 1. The corresponding header for source files.
840 2. C system files in alphabetical order
841 3. C++ system files in alphabetical order
842 4. Project's .h files in alphabetical order
843
[email protected]ac294a12012-12-06 16:38:43844 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
845 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28846 """
[email protected]e120b012014-08-15 19:08:35847 def FileFilterIncludeOrder(affected_file):
848 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
849 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28850
851 warnings = []
[email protected]e120b012014-08-15 19:08:35852 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08853 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43854 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
855 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28856
857 results = []
858 if warnings:
[email protected]f7051d52013-04-02 18:31:42859 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53860 warnings))
[email protected]cf9b78f2012-11-14 11:40:28861 return results
862
863
[email protected]70ca77752012-11-20 03:45:03864def _CheckForVersionControlConflictsInFile(input_api, f):
865 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
866 errors = []
867 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23868 if f.LocalPath().endswith('.md'):
869 # First-level headers in markdown look a lot like version control
870 # conflict markers. http://daringfireball.net/projects/markdown/basics
871 continue
[email protected]70ca77752012-11-20 03:45:03872 if pattern.match(line):
873 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
874 return errors
875
876
877def _CheckForVersionControlConflicts(input_api, output_api):
878 """Usually this is not intentional and will cause a compile failure."""
879 errors = []
880 for f in input_api.AffectedFiles():
881 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
882
883 results = []
884 if errors:
885 results.append(output_api.PresubmitError(
886 'Version control conflict markers found, please resolve.', errors))
887 return results
888
889
[email protected]06e6d0ff2012-12-11 01:36:44890def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
891 def FilterFile(affected_file):
892 """Filter function for use with input_api.AffectedSourceFiles,
893 below. This filters out everything except non-test files from
894 top-level directories that generally speaking should not hard-code
895 service URLs (e.g. src/android_webview/, src/content/ and others).
896 """
897 return input_api.FilterSourceFile(
898 affected_file,
[email protected]78bb39d62012-12-11 15:11:56899 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44900 black_list=(_EXCLUDED_PATHS +
901 _TEST_CODE_EXCLUDED_PATHS +
902 input_api.DEFAULT_BLACK_LIST))
903
reillyi38965732015-11-16 18:27:33904 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
905 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46906 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
907 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44908 problems = [] # items are (filename, line_number, line)
909 for f in input_api.AffectedSourceFiles(FilterFile):
910 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46911 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44912 problems.append((f.LocalPath(), line_num, line))
913
914 if problems:
[email protected]f7051d52013-04-02 18:31:42915 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44916 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58917 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44918 [' %s:%d: %s' % (
919 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03920 else:
921 return []
[email protected]06e6d0ff2012-12-11 01:36:44922
923
[email protected]d2530012013-01-25 16:39:27924def _CheckNoAbbreviationInPngFileName(input_api, output_api):
925 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31926 The native_client_sdk directory is excluded because it has auto-generated PNG
927 files for documentation.
[email protected]d2530012013-01-25 16:39:27928 """
[email protected]d2530012013-01-25 16:39:27929 errors = []
binji0dcdf342014-12-12 18:32:31930 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
931 black_list = (r'^native_client_sdk[\\\/]',)
932 file_filter = lambda f: input_api.FilterSourceFile(
933 f, white_list=white_list, black_list=black_list)
934 for f in input_api.AffectedFiles(include_deletes=False,
935 file_filter=file_filter):
936 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27937
938 results = []
939 if errors:
940 results.append(output_api.PresubmitError(
941 'The name of PNG files should not have abbreviations. \n'
942 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
943 'Contact [email protected] if you have questions.', errors))
944 return results
945
946
[email protected]14a6131c2014-01-08 01:15:41947def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08948 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41949 a set of DEPS entries that we should look up.
950
951 For a directory (rather than a specific filename) we fake a path to
952 a specific filename by adding /DEPS. This is chosen as a file that
953 will seldom or never be subject to per-file include_rules.
954 """
[email protected]2b438d62013-11-14 17:54:14955 # We ignore deps entries on auto-generated directories.
956 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08957
958 # This pattern grabs the path without basename in the first
959 # parentheses, and the basename (if present) in the second. It
960 # relies on the simple heuristic that if there is a basename it will
961 # be a header file ending in ".h".
962 pattern = re.compile(
963 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14964 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08965 for changed_line in changed_lines:
966 m = pattern.match(changed_line)
967 if m:
968 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14969 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41970 if m.group(2):
971 results.add('%s%s' % (path, m.group(2)))
972 else:
973 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08974 return results
975
976
[email protected]e871964c2013-05-13 14:14:55977def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
978 """When a dependency prefixed with + is added to a DEPS file, we
979 want to make sure that the change is reviewed by an OWNER of the
980 target file or directory, to avoid layering violations from being
981 introduced. This check verifies that this happens.
982 """
983 changed_lines = set()
984 for f in input_api.AffectedFiles():
985 filename = input_api.os_path.basename(f.LocalPath())
986 if filename == 'DEPS':
987 changed_lines |= set(line.strip()
988 for line_num, line
989 in f.ChangedContents())
990 if not changed_lines:
991 return []
992
[email protected]14a6131c2014-01-08 01:15:41993 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
994 changed_lines)
[email protected]e871964c2013-05-13 14:14:55995 if not virtual_depended_on_files:
996 return []
997
998 if input_api.is_committing:
999 if input_api.tbr:
1000 return [output_api.PresubmitNotifyResult(
1001 '--tbr was specified, skipping OWNERS check for DEPS additions')]
1002 if not input_api.change.issue:
1003 return [output_api.PresubmitError(
1004 "DEPS approval by OWNERS check failed: this change has "
1005 "no Rietveld issue number, so we can't check it for approvals.")]
1006 output = output_api.PresubmitError
1007 else:
1008 output = output_api.PresubmitNotifyResult
1009
1010 owners_db = input_api.owners_db
1011 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
1012 input_api,
1013 owners_db.email_regexp,
1014 approval_needed=input_api.is_committing)
1015
1016 owner_email = owner_email or input_api.change.author_email
1017
[email protected]de4f7d22013-05-23 14:27:461018 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511019 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461020 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551021 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1022 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411023
1024 # We strip the /DEPS part that was added by
1025 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1026 # directory.
1027 def StripDeps(path):
1028 start_deps = path.rfind('/DEPS')
1029 if start_deps != -1:
1030 return path[:start_deps]
1031 else:
1032 return path
1033 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551034 for path in missing_files]
1035
1036 if unapproved_dependencies:
1037 output_list = [
[email protected]14a6131c2014-01-08 01:15:411038 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551039 '\n '.join(sorted(unapproved_dependencies)))]
1040 if not input_api.is_committing:
1041 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1042 output_list.append(output(
1043 'Suggested missing target path OWNERS:\n %s' %
1044 '\n '.join(suggested_owners or [])))
1045 return output_list
1046
1047 return []
1048
1049
[email protected]85218562013-11-22 07:41:401050def _CheckSpamLogging(input_api, output_api):
1051 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1052 black_list = (_EXCLUDED_PATHS +
1053 _TEST_CODE_EXCLUDED_PATHS +
1054 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501055 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191056 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481057 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461058 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121059 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1060 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581061 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161062 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031063 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151064 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1065 r"^chromecast[\\\/]",
1066 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311067 r"^components[\\\/]html_viewer[\\\/]"
1068 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461069 # TODO(peter): Remove this exception. https://crbug.com/534537
1070 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1071 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251072 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1073 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111074 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151075 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111076 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521077 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501078 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361079 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311080 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131081 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441082 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021083 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441084 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401085 source_file_filter = lambda x: input_api.FilterSourceFile(
1086 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1087
1088 log_info = []
1089 printf = []
1090
1091 for f in input_api.AffectedSourceFiles(source_file_filter):
1092 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471093 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401094 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471095 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131096 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371097
mohan.reddyf21db962014-10-16 12:26:471098 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371099 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471100 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401101 printf.append(f.LocalPath())
1102
1103 if log_info:
1104 return [output_api.PresubmitError(
1105 'These files spam the console log with LOG(INFO):',
1106 items=log_info)]
1107 if printf:
1108 return [output_api.PresubmitError(
1109 'These files spam the console log with printf/fprintf:',
1110 items=printf)]
1111 return []
1112
1113
[email protected]49aa76a2013-12-04 06:59:161114def _CheckForAnonymousVariables(input_api, output_api):
1115 """These types are all expected to hold locks while in scope and
1116 so should never be anonymous (which causes them to be immediately
1117 destroyed)."""
1118 they_who_must_be_named = [
1119 'base::AutoLock',
1120 'base::AutoReset',
1121 'base::AutoUnlock',
1122 'SkAutoAlphaRestore',
1123 'SkAutoBitmapShaderInstall',
1124 'SkAutoBlitterChoose',
1125 'SkAutoBounderCommit',
1126 'SkAutoCallProc',
1127 'SkAutoCanvasRestore',
1128 'SkAutoCommentBlock',
1129 'SkAutoDescriptor',
1130 'SkAutoDisableDirectionCheck',
1131 'SkAutoDisableOvalCheck',
1132 'SkAutoFree',
1133 'SkAutoGlyphCache',
1134 'SkAutoHDC',
1135 'SkAutoLockColors',
1136 'SkAutoLockPixels',
1137 'SkAutoMalloc',
1138 'SkAutoMaskFreeImage',
1139 'SkAutoMutexAcquire',
1140 'SkAutoPathBoundsUpdate',
1141 'SkAutoPDFRelease',
1142 'SkAutoRasterClipValidate',
1143 'SkAutoRef',
1144 'SkAutoTime',
1145 'SkAutoTrace',
1146 'SkAutoUnref',
1147 ]
1148 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1149 # bad: base::AutoLock(lock.get());
1150 # not bad: base::AutoLock lock(lock.get());
1151 bad_pattern = input_api.re.compile(anonymous)
1152 # good: new base::AutoLock(lock.get())
1153 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1154 errors = []
1155
1156 for f in input_api.AffectedFiles():
1157 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1158 continue
1159 for linenum, line in f.ChangedContents():
1160 if bad_pattern.search(line) and not good_pattern.search(line):
1161 errors.append('%s:%d' % (f.LocalPath(), linenum))
1162
1163 if errors:
1164 return [output_api.PresubmitError(
1165 'These lines create anonymous variables that need to be named:',
1166 items=errors)]
1167 return []
1168
1169
[email protected]5fe0f8742013-11-29 01:04:591170def _CheckCygwinShell(input_api, output_api):
1171 source_file_filter = lambda x: input_api.FilterSourceFile(
1172 x, white_list=(r'.+\.(gyp|gypi)$',))
1173 cygwin_shell = []
1174
1175 for f in input_api.AffectedSourceFiles(source_file_filter):
1176 for linenum, line in f.ChangedContents():
1177 if 'msvs_cygwin_shell' in line:
1178 cygwin_shell.append(f.LocalPath())
1179 break
1180
1181 if cygwin_shell:
1182 return [output_api.PresubmitError(
1183 'These files should not use msvs_cygwin_shell (the default is 0):',
1184 items=cygwin_shell)]
1185 return []
1186
[email protected]85218562013-11-22 07:41:401187
[email protected]999261d2014-03-03 20:08:081188def _CheckUserActionUpdate(input_api, output_api):
1189 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521190 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081191 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521192 # If actions.xml is already included in the changelist, the PRESUBMIT
1193 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081194 return []
1195
[email protected]999261d2014-03-03 20:08:081196 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1197 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521198 current_actions = None
[email protected]999261d2014-03-03 20:08:081199 for f in input_api.AffectedFiles(file_filter=file_filter):
1200 for line_num, line in f.ChangedContents():
1201 match = input_api.re.search(action_re, line)
1202 if match:
[email protected]2f92dec2014-03-07 19:21:521203 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1204 # loaded only once.
1205 if not current_actions:
1206 with open('tools/metrics/actions/actions.xml') as actions_f:
1207 current_actions = actions_f.read()
1208 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081209 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521210 action = 'name="{0}"'.format(action_name)
1211 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081212 return [output_api.PresubmitPromptWarning(
1213 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521214 'tools/metrics/actions/actions.xml. Please run '
1215 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081216 % (f.LocalPath(), line_num, action_name))]
1217 return []
1218
1219
[email protected]99171a92014-06-03 08:44:471220def _GetJSONParseError(input_api, filename, eat_comments=True):
1221 try:
1222 contents = input_api.ReadFile(filename)
1223 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131224 import sys
1225 original_sys_path = sys.path
1226 try:
1227 sys.path = sys.path + [input_api.os_path.join(
1228 input_api.PresubmitLocalPath(),
1229 'tools', 'json_comment_eater')]
1230 import json_comment_eater
1231 finally:
1232 sys.path = original_sys_path
1233 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471234
1235 input_api.json.loads(contents)
1236 except ValueError as e:
1237 return e
1238 return None
1239
1240
1241def _GetIDLParseError(input_api, filename):
1242 try:
1243 contents = input_api.ReadFile(filename)
1244 idl_schema = input_api.os_path.join(
1245 input_api.PresubmitLocalPath(),
1246 'tools', 'json_schema_compiler', 'idl_schema.py')
1247 process = input_api.subprocess.Popen(
1248 [input_api.python_executable, idl_schema],
1249 stdin=input_api.subprocess.PIPE,
1250 stdout=input_api.subprocess.PIPE,
1251 stderr=input_api.subprocess.PIPE,
1252 universal_newlines=True)
1253 (_, error) = process.communicate(input=contents)
1254 return error or None
1255 except ValueError as e:
1256 return e
1257
1258
1259def _CheckParseErrors(input_api, output_api):
1260 """Check that IDL and JSON files do not contain syntax errors."""
1261 actions = {
1262 '.idl': _GetIDLParseError,
1263 '.json': _GetJSONParseError,
1264 }
1265 # These paths contain test data and other known invalid JSON files.
1266 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491267 r'test[\\\/]data[\\\/]',
1268 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471269 ]
1270 # Most JSON files are preprocessed and support comments, but these do not.
1271 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491272 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471273 ]
1274 # Only run IDL checker on files in these directories.
1275 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491276 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1277 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471278 ]
1279
1280 def get_action(affected_file):
1281 filename = affected_file.LocalPath()
1282 return actions.get(input_api.os_path.splitext(filename)[1])
1283
1284 def MatchesFile(patterns, path):
1285 for pattern in patterns:
1286 if input_api.re.search(pattern, path):
1287 return True
1288 return False
1289
1290 def FilterFile(affected_file):
1291 action = get_action(affected_file)
1292 if not action:
1293 return False
1294 path = affected_file.LocalPath()
1295
1296 if MatchesFile(excluded_patterns, path):
1297 return False
1298
1299 if (action == _GetIDLParseError and
1300 not MatchesFile(idl_included_patterns, path)):
1301 return False
1302 return True
1303
1304 results = []
1305 for affected_file in input_api.AffectedFiles(
1306 file_filter=FilterFile, include_deletes=False):
1307 action = get_action(affected_file)
1308 kwargs = {}
1309 if (action == _GetJSONParseError and
1310 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1311 kwargs['eat_comments'] = False
1312 parse_error = action(input_api,
1313 affected_file.AbsoluteLocalPath(),
1314 **kwargs)
1315 if parse_error:
1316 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1317 (affected_file.LocalPath(), parse_error)))
1318 return results
1319
1320
[email protected]760deea2013-12-10 19:33:491321def _CheckJavaStyle(input_api, output_api):
1322 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471323 import sys
[email protected]760deea2013-12-10 19:33:491324 original_sys_path = sys.path
1325 try:
1326 sys.path = sys.path + [input_api.os_path.join(
1327 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1328 import checkstyle
1329 finally:
1330 # Restore sys.path to what it was before.
1331 sys.path = original_sys_path
1332
1333 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091334 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511335 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491336
1337
dskiba88634f4e2015-08-14 23:03:291338def _CheckAndroidToastUsage(input_api, output_api):
1339 """Checks that code uses org.chromium.ui.widget.Toast instead of
1340 android.widget.Toast (Chromium Toast doesn't force hardware
1341 acceleration on low-end devices, saving memory).
1342 """
1343 toast_import_pattern = input_api.re.compile(
1344 r'^import android\.widget\.Toast;$')
1345
1346 errors = []
1347
1348 sources = lambda affected_file: input_api.FilterSourceFile(
1349 affected_file,
1350 black_list=(_EXCLUDED_PATHS +
1351 _TEST_CODE_EXCLUDED_PATHS +
1352 input_api.DEFAULT_BLACK_LIST +
1353 (r'^chromecast[\\\/].*',
1354 r'^remoting[\\\/].*')),
1355 white_list=(r'.*\.java$',))
1356
1357 for f in input_api.AffectedSourceFiles(sources):
1358 for line_num, line in f.ChangedContents():
1359 if toast_import_pattern.search(line):
1360 errors.append("%s:%d" % (f.LocalPath(), line_num))
1361
1362 results = []
1363
1364 if errors:
1365 results.append(output_api.PresubmitError(
1366 'android.widget.Toast usage is detected. Android toasts use hardware'
1367 ' acceleration, and can be\ncostly on low-end devices. Please use'
1368 ' org.chromium.ui.widget.Toast instead.\n'
1369 'Contact [email protected] if you have any questions.',
1370 errors))
1371
1372 return results
1373
1374
dgnaa68d5e2015-06-10 10:08:221375def _CheckAndroidCrLogUsage(input_api, output_api):
1376 """Checks that new logs using org.chromium.base.Log:
1377 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511378 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221379 """
1380 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121381 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1382 class_in_base_pattern = input_api.re.compile(
1383 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1384 has_some_log_import_pattern = input_api.re.compile(
1385 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221386 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121387 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221388 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511389 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221390 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221391
Vincent Scheib16d7b272015-09-15 18:09:071392 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221393 'or contact [email protected] for more info.')
1394 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121395
dgnaa68d5e2015-06-10 10:08:221396 tag_decl_errors = []
1397 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121398 tag_errors = []
dgn38736db2015-09-18 19:20:511399 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121400 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221401
1402 for f in input_api.AffectedSourceFiles(sources):
1403 file_content = input_api.ReadFile(f)
1404 has_modified_logs = False
1405
1406 # Per line checks
dgn87d9fb62015-06-12 09:15:121407 if (cr_log_import_pattern.search(file_content) or
1408 (class_in_base_pattern.search(file_content) and
1409 not has_some_log_import_pattern.search(file_content))):
1410 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221411 for line_num, line in f.ChangedContents():
1412
1413 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121414 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221415 if match:
1416 has_modified_logs = True
1417
1418 # Make sure it uses "TAG"
1419 if not match.group('tag') == 'TAG':
1420 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121421 else:
1422 # Report non cr Log function calls in changed lines
1423 for line_num, line in f.ChangedContents():
1424 if log_call_pattern.search(line):
1425 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221426
1427 # Per file checks
1428 if has_modified_logs:
1429 # Make sure the tag is using the "cr" prefix and is not too long
1430 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511431 tag_name = match.group('name') if match else None
1432 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221433 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511434 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221435 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511436 elif '.' in tag_name:
1437 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221438
1439 results = []
1440 if tag_decl_errors:
1441 results.append(output_api.PresubmitPromptWarning(
1442 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511443 '"private static final String TAG = "<package tag>".\n'
1444 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221445 tag_decl_errors))
1446
1447 if tag_length_errors:
1448 results.append(output_api.PresubmitError(
1449 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511450 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221451 tag_length_errors))
1452
1453 if tag_errors:
1454 results.append(output_api.PresubmitPromptWarning(
1455 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1456 tag_errors))
1457
dgn87d9fb62015-06-12 09:15:121458 if util_log_errors:
dgn4401aa52015-04-29 16:26:171459 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121460 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1461 util_log_errors))
1462
dgn38736db2015-09-18 19:20:511463 if tag_with_dot_errors:
1464 results.append(output_api.PresubmitPromptWarning(
1465 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1466 tag_with_dot_errors))
1467
dgn4401aa52015-04-29 16:26:171468 return results
1469
1470
agrieve7b6479d82015-10-07 14:24:221471def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1472 """Checks if MDPI assets are placed in a correct directory."""
1473 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1474 ('/res/drawable/' in f.LocalPath() or
1475 '/res/drawable-ldrtl/' in f.LocalPath()))
1476 errors = []
1477 for f in input_api.AffectedFiles(include_deletes=False,
1478 file_filter=file_filter):
1479 errors.append(' %s' % f.LocalPath())
1480
1481 results = []
1482 if errors:
1483 results.append(output_api.PresubmitError(
1484 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1485 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1486 '/res/drawable-ldrtl/.\n'
1487 'Contact [email protected] if you have questions.', errors))
1488 return results
1489
1490
mnaganov9b9b1fe82014-12-11 16:30:361491def _CheckForCopyrightedCode(input_api, output_api):
1492 """Verifies that newly added code doesn't contain copyrighted material
1493 and is properly licensed under the standard Chromium license.
1494
1495 As there can be false positives, we maintain a whitelist file. This check
1496 also verifies that the whitelist file is up to date.
1497 """
1498 import sys
1499 original_sys_path = sys.path
1500 try:
1501 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221502 input_api.PresubmitLocalPath(), 'tools')]
1503 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361504 finally:
1505 # Restore sys.path to what it was before.
1506 sys.path = original_sys_path
1507
1508 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1509
1510
glidere61efad2015-02-18 17:39:431511def _CheckSingletonInHeaders(input_api, output_api):
1512 """Checks to make sure no header files have |Singleton<|."""
1513 def FileFilter(affected_file):
1514 # It's ok for base/memory/singleton.h to have |Singleton<|.
1515 black_list = (_EXCLUDED_PATHS +
1516 input_api.DEFAULT_BLACK_LIST +
1517 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1518 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1519
sergeyu34d21222015-09-16 00:11:441520 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431521 files = []
1522 for f in input_api.AffectedSourceFiles(FileFilter):
1523 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1524 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1525 contents = input_api.ReadFile(f)
1526 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241527 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431528 pattern.search(line)):
1529 files.append(f)
1530 break
1531
1532 if files:
1533 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441534 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431535 'Please move them to an appropriate source file so that the ' +
1536 'template gets instantiated in a single compilation unit.',
1537 files) ]
1538 return []
1539
1540
[email protected]fd20b902014-05-09 02:14:531541_DEPRECATED_CSS = [
1542 # Values
1543 ( "-webkit-box", "flex" ),
1544 ( "-webkit-inline-box", "inline-flex" ),
1545 ( "-webkit-flex", "flex" ),
1546 ( "-webkit-inline-flex", "inline-flex" ),
1547 ( "-webkit-min-content", "min-content" ),
1548 ( "-webkit-max-content", "max-content" ),
1549
1550 # Properties
1551 ( "-webkit-background-clip", "background-clip" ),
1552 ( "-webkit-background-origin", "background-origin" ),
1553 ( "-webkit-background-size", "background-size" ),
1554 ( "-webkit-box-shadow", "box-shadow" ),
1555
1556 # Functions
1557 ( "-webkit-gradient", "gradient" ),
1558 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1559 ( "-webkit-linear-gradient", "linear-gradient" ),
1560 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1561 ( "-webkit-radial-gradient", "radial-gradient" ),
1562 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1563]
1564
1565def _CheckNoDeprecatedCSS(input_api, output_api):
1566 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251567 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341568 documentation and iOS CSS for dom distiller
1569 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251570 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531571 results = []
dbeam070cfe62014-10-22 06:44:021572 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251573 black_list = (_EXCLUDED_PATHS +
1574 _TEST_CODE_EXCLUDED_PATHS +
1575 input_api.DEFAULT_BLACK_LIST +
1576 (r"^chrome/common/extensions/docs",
1577 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341578 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051579 r"^components/flags_ui/resources/apple_flags.css",
[email protected]9a48e3f82014-05-22 00:06:251580 r"^native_client_sdk"))
1581 file_filter = lambda f: input_api.FilterSourceFile(
1582 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531583 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1584 for line_num, line in fpath.ChangedContents():
1585 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021586 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531587 results.append(output_api.PresubmitError(
1588 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1589 (fpath.LocalPath(), line_num, deprecated_value, value)))
1590 return results
1591
mohan.reddyf21db962014-10-16 12:26:471592
dbeam070cfe62014-10-22 06:44:021593_DEPRECATED_JS = [
1594 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1595 ( "__defineGetter__", "Object.defineProperty" ),
1596 ( "__defineSetter__", "Object.defineProperty" ),
1597]
1598
1599def _CheckNoDeprecatedJS(input_api, output_api):
1600 """Make sure that we don't use deprecated JS in Chrome code."""
1601 results = []
1602 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1603 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1604 input_api.DEFAULT_BLACK_LIST)
1605 file_filter = lambda f: input_api.FilterSourceFile(
1606 f, white_list=file_inclusion_pattern, black_list=black_list)
1607 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1608 for lnum, line in fpath.ChangedContents():
1609 for (deprecated, replacement) in _DEPRECATED_JS:
1610 if deprecated in line:
1611 results.append(output_api.PresubmitError(
1612 "%s:%d: Use of deprecated JS %s, use %s instead" %
1613 (fpath.LocalPath(), lnum, deprecated, replacement)))
1614 return results
1615
1616
dgnaa68d5e2015-06-10 10:08:221617def _AndroidSpecificOnUploadChecks(input_api, output_api):
1618 """Groups checks that target android code."""
1619 results = []
dgnaa68d5e2015-06-10 10:08:221620 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221621 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291622 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221623 return results
1624
1625
[email protected]22c9bd72011-03-27 16:47:391626def _CommonChecks(input_api, output_api):
1627 """Checks common to both upload and commit."""
1628 results = []
1629 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381630 input_api, output_api,
1631 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461632 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191633 results.extend(
[email protected]760deea2013-12-10 19:33:491634 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541635 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181636 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:521637 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221638 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441639 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591640 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061641 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121642 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181643 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221644 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491645 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271646 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031647 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491648 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441649 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271650 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541651 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441652 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461653 # TODO(danakj): Remove this when base/move.h is removed.
1654 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551655 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041656 results.extend(
1657 input_api.canned_checks.CheckChangeHasNoTabs(
1658 input_api,
1659 output_api,
1660 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401661 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161662 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591663 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081664 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531665 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021666 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471667 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041668 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361669 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231670 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431671 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241672
1673 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1674 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1675 input_api, output_api,
1676 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381677 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391678 return results
[email protected]1f7b4172010-01-28 01:17:341679
[email protected]b337cb5b2011-01-23 21:24:051680
[email protected]66daa702011-05-28 14:41:461681def _CheckAuthorizedAuthor(input_api, output_api):
1682 """For non-googler/chromites committers, verify the author's email address is
1683 in AUTHORS.
1684 """
[email protected]9bb9cb82011-06-13 20:43:011685 # TODO(maruel): Add it to input_api?
1686 import fnmatch
1687
[email protected]66daa702011-05-28 14:41:461688 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011689 if not author:
1690 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461691 return []
[email protected]c99663292011-05-31 19:46:081692 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461693 input_api.PresubmitLocalPath(), 'AUTHORS')
1694 valid_authors = (
1695 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1696 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181697 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441698 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231699 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461700 return [output_api.PresubmitPromptWarning(
1701 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1702 '\n'
1703 'http://www.chromium.org/developers/contributing-code and read the '
1704 '"Legal" section\n'
1705 'If you are a chromite, verify the contributor signed the CLA.') %
1706 author)]
1707 return []
1708
1709
[email protected]b8079ae4a2012-12-05 19:56:491710def _CheckPatchFiles(input_api, output_api):
1711 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1712 if f.LocalPath().endswith(('.orig', '.rej'))]
1713 if problems:
1714 return [output_api.PresubmitError(
1715 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031716 else:
1717 return []
[email protected]b8079ae4a2012-12-05 19:56:491718
1719
[email protected]b00342e7f2013-03-26 16:21:541720def _DidYouMeanOSMacro(bad_macro):
1721 try:
1722 return {'A': 'OS_ANDROID',
1723 'B': 'OS_BSD',
1724 'C': 'OS_CHROMEOS',
1725 'F': 'OS_FREEBSD',
1726 'L': 'OS_LINUX',
1727 'M': 'OS_MACOSX',
1728 'N': 'OS_NACL',
1729 'O': 'OS_OPENBSD',
1730 'P': 'OS_POSIX',
1731 'S': 'OS_SOLARIS',
1732 'W': 'OS_WIN'}[bad_macro[3].upper()]
1733 except KeyError:
1734 return ''
1735
1736
1737def _CheckForInvalidOSMacrosInFile(input_api, f):
1738 """Check for sensible looking, totally invalid OS macros."""
1739 preprocessor_statement = input_api.re.compile(r'^\s*#')
1740 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1741 results = []
1742 for lnum, line in f.ChangedContents():
1743 if preprocessor_statement.search(line):
1744 for match in os_macro.finditer(line):
1745 if not match.group(1) in _VALID_OS_MACROS:
1746 good = _DidYouMeanOSMacro(match.group(1))
1747 did_you_mean = ' (did you mean %s?)' % good if good else ''
1748 results.append(' %s:%d %s%s' % (f.LocalPath(),
1749 lnum,
1750 match.group(1),
1751 did_you_mean))
1752 return results
1753
1754
1755def _CheckForInvalidOSMacros(input_api, output_api):
1756 """Check all affected files for invalid OS macros."""
1757 bad_macros = []
1758 for f in input_api.AffectedFiles():
1759 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1760 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1761
1762 if not bad_macros:
1763 return []
1764
1765 return [output_api.PresubmitError(
1766 'Possibly invalid OS macro[s] found. Please fix your code\n'
1767 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1768
lliabraa35bab3932014-10-01 12:16:441769
1770def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1771 """Check all affected files for invalid "if defined" macros."""
1772 ALWAYS_DEFINED_MACROS = (
1773 "TARGET_CPU_PPC",
1774 "TARGET_CPU_PPC64",
1775 "TARGET_CPU_68K",
1776 "TARGET_CPU_X86",
1777 "TARGET_CPU_ARM",
1778 "TARGET_CPU_MIPS",
1779 "TARGET_CPU_SPARC",
1780 "TARGET_CPU_ALPHA",
1781 "TARGET_IPHONE_SIMULATOR",
1782 "TARGET_OS_EMBEDDED",
1783 "TARGET_OS_IPHONE",
1784 "TARGET_OS_MAC",
1785 "TARGET_OS_UNIX",
1786 "TARGET_OS_WIN32",
1787 )
1788 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1789 results = []
1790 for lnum, line in f.ChangedContents():
1791 for match in ifdef_macro.finditer(line):
1792 if match.group(1) in ALWAYS_DEFINED_MACROS:
1793 always_defined = ' %s is always defined. ' % match.group(1)
1794 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1795 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1796 lnum,
1797 always_defined,
1798 did_you_mean))
1799 return results
1800
1801
1802def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1803 """Check all affected files for invalid "if defined" macros."""
1804 bad_macros = []
1805 for f in input_api.AffectedFiles():
1806 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1807 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1808
1809 if not bad_macros:
1810 return []
1811
1812 return [output_api.PresubmitError(
1813 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1814 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1815 bad_macros)]
1816
1817
danakj3c84d0c2014-10-06 15:35:461818def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1819 """Check all affected files for using side effects of Pass."""
1820 errors = []
1821 for f in input_api.AffectedFiles():
1822 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1823 for lnum, line in f.ChangedContents():
1824 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471825 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461826 errors.append(output_api.PresubmitError(
1827 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1828 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1829 return errors
1830
1831
mlamouria82272622014-09-16 18:45:041832def _CheckForIPCRules(input_api, output_api):
1833 """Check for same IPC rules described in
1834 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1835 """
1836 base_pattern = r'IPC_ENUM_TRAITS\('
1837 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1838 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1839
1840 problems = []
1841 for f in input_api.AffectedSourceFiles(None):
1842 local_path = f.LocalPath()
1843 if not local_path.endswith('.h'):
1844 continue
1845 for line_number, line in f.ChangedContents():
1846 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1847 problems.append(
1848 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1849
1850 if problems:
1851 return [output_api.PresubmitPromptWarning(
1852 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1853 else:
1854 return []
1855
[email protected]b00342e7f2013-03-26 16:21:541856
mostynbb639aca52015-01-07 20:31:231857def _CheckForWindowsLineEndings(input_api, output_api):
1858 """Check source code and known ascii text files for Windows style line
1859 endings.
1860 """
earthdok1b5e0ee2015-03-10 15:19:101861 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231862
1863 file_inclusion_pattern = (
1864 known_text_files,
1865 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1866 )
1867
1868 filter = lambda f: input_api.FilterSourceFile(
1869 f, white_list=file_inclusion_pattern, black_list=None)
1870 files = [f.LocalPath() for f in
1871 input_api.AffectedSourceFiles(filter)]
1872
1873 problems = []
1874
1875 for file in files:
1876 fp = open(file, 'r')
1877 for line in fp:
1878 if line.endswith('\r\n'):
1879 problems.append(file)
1880 break
1881 fp.close()
1882
1883 if problems:
1884 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1885 'these files to contain Windows style line endings?\n' +
1886 '\n'.join(problems))]
1887
1888 return []
1889
1890
[email protected]1f7b4172010-01-28 01:17:341891def CheckChangeOnUpload(input_api, output_api):
1892 results = []
1893 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471894 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171895 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281896 results.extend(
1897 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191898 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221899 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541900 return results
[email protected]ca8d1982009-02-19 16:33:121901
1902
[email protected]1bfb8322014-04-23 01:02:411903def GetTryServerMasterForBot(bot):
1904 """Returns the Try Server master for the given bot.
1905
[email protected]0bb112362014-07-26 04:38:321906 It tries to guess the master from the bot name, but may still fail
1907 and return None. There is no longer a default master.
1908 """
1909 # Potentially ambiguous bot names are listed explicitly.
1910 master_map = {
[email protected]0bb112362014-07-26 04:38:321911 'chromium_presubmit': 'tryserver.chromium.linux',
1912 'blink_presubmit': 'tryserver.chromium.linux',
1913 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411914 }
[email protected]0bb112362014-07-26 04:38:321915 master = master_map.get(bot)
1916 if not master:
sergiyb37fd293f2015-02-26 06:55:011917 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321918 master = 'tryserver.chromium.linux'
1919 elif 'win' in bot:
1920 master = 'tryserver.chromium.win'
1921 elif 'mac' in bot or 'ios' in bot:
1922 master = 'tryserver.chromium.mac'
1923 return master
[email protected]1bfb8322014-04-23 01:02:411924
1925
Paweł Hajdan, Jr55083782014-12-19 20:32:561926def GetDefaultTryConfigs(bots):
1927 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011928 """
1929
Paweł Hajdan, Jr55083782014-12-19 20:32:561930 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411931
1932 # Build up the mapping from tryserver master to bot/test.
1933 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561934 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411935 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1936 return out
[email protected]38c6a512013-12-18 23:48:011937
1938
[email protected]ca8d1982009-02-19 16:33:121939def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541940 results = []
[email protected]1f7b4172010-01-28 01:17:341941 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541942 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271943 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341944 input_api,
1945 output_api,
[email protected]2fdd1f362013-01-16 03:56:031946 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271947
[email protected]3e4eb112011-01-18 03:29:541948 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1949 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411950 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1951 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541952 return results
[email protected]ca8d1982009-02-19 16:33:121953
1954
[email protected]7468ac522014-03-12 23:35:571955def GetPreferredTryMasters(project, change):
Paweł Hajdan, Jref2afd42015-01-07 15:59:521956 import json
sergiyb57a71e32015-06-03 18:44:001957 import os.path
1958 import platform
1959 import subprocess
smut3ef206e12015-03-20 09:30:001960
sergiyb57a71e32015-06-03 18:44:001961 cq_config_path = os.path.join(
1962 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
1963 # commit_queue.py below is a script in depot_tools directory, which has a
1964 # 'builders' command to retrieve a list of CQ builders from the CQ config.
1965 is_win = platform.system() == 'Windows'
1966 masters = json.loads(subprocess.check_output(
1967 ['commit_queue', 'builders', cq_config_path], shell=is_win))
[email protected]911753b2012-08-02 12:11:541968
sergiyb6092f742015-06-16 09:00:521969 try_config = {}
1970 for master in masters:
1971 try_config.setdefault(master, {})
1972 for builder in masters[master]:
sergiyb57a71e32015-06-03 18:44:001973 # Do not trigger presubmit builders, since they're likely to fail
1974 # (e.g. OWNERS checks before finished code review), and we're
1975 # running local presubmit anyway.
sergiyb6092f742015-06-16 09:00:521976 if 'presubmit' not in builder:
1977 try_config[master][builder] = ['defaulttests']
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321978
sergiyb6092f742015-06-16 09:00:521979 return try_config