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