blob: e3ee9c4715bcf7cbc50c56129abb3f91ac142b0d [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()]
phajdan.jr5ea54792015-10-14 10:51:11659 try:
660 input_api.subprocess.check_output(args)
661 return []
662 except input_api.subprocess.CalledProcessError as error:
663 return [output_api.PresubmitError(
664 'checkperms.py failed:',
665 long_text=error.output)]
[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$",
peter80739bb2015-10-20 11:17:461051 # TODO(peter): Remove this exception. https://crbug.com/534537
1052 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1053 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251054 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1055 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111056 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151057 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111058 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521059 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501060 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361061 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311062 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131063 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441064 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021065 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441066 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401067 source_file_filter = lambda x: input_api.FilterSourceFile(
1068 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1069
1070 log_info = []
1071 printf = []
1072
1073 for f in input_api.AffectedSourceFiles(source_file_filter):
1074 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471075 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401076 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471077 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131078 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371079
mohan.reddyf21db962014-10-16 12:26:471080 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371081 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471082 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401083 printf.append(f.LocalPath())
1084
1085 if log_info:
1086 return [output_api.PresubmitError(
1087 'These files spam the console log with LOG(INFO):',
1088 items=log_info)]
1089 if printf:
1090 return [output_api.PresubmitError(
1091 'These files spam the console log with printf/fprintf:',
1092 items=printf)]
1093 return []
1094
1095
[email protected]49aa76a2013-12-04 06:59:161096def _CheckForAnonymousVariables(input_api, output_api):
1097 """These types are all expected to hold locks while in scope and
1098 so should never be anonymous (which causes them to be immediately
1099 destroyed)."""
1100 they_who_must_be_named = [
1101 'base::AutoLock',
1102 'base::AutoReset',
1103 'base::AutoUnlock',
1104 'SkAutoAlphaRestore',
1105 'SkAutoBitmapShaderInstall',
1106 'SkAutoBlitterChoose',
1107 'SkAutoBounderCommit',
1108 'SkAutoCallProc',
1109 'SkAutoCanvasRestore',
1110 'SkAutoCommentBlock',
1111 'SkAutoDescriptor',
1112 'SkAutoDisableDirectionCheck',
1113 'SkAutoDisableOvalCheck',
1114 'SkAutoFree',
1115 'SkAutoGlyphCache',
1116 'SkAutoHDC',
1117 'SkAutoLockColors',
1118 'SkAutoLockPixels',
1119 'SkAutoMalloc',
1120 'SkAutoMaskFreeImage',
1121 'SkAutoMutexAcquire',
1122 'SkAutoPathBoundsUpdate',
1123 'SkAutoPDFRelease',
1124 'SkAutoRasterClipValidate',
1125 'SkAutoRef',
1126 'SkAutoTime',
1127 'SkAutoTrace',
1128 'SkAutoUnref',
1129 ]
1130 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1131 # bad: base::AutoLock(lock.get());
1132 # not bad: base::AutoLock lock(lock.get());
1133 bad_pattern = input_api.re.compile(anonymous)
1134 # good: new base::AutoLock(lock.get())
1135 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1136 errors = []
1137
1138 for f in input_api.AffectedFiles():
1139 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1140 continue
1141 for linenum, line in f.ChangedContents():
1142 if bad_pattern.search(line) and not good_pattern.search(line):
1143 errors.append('%s:%d' % (f.LocalPath(), linenum))
1144
1145 if errors:
1146 return [output_api.PresubmitError(
1147 'These lines create anonymous variables that need to be named:',
1148 items=errors)]
1149 return []
1150
1151
[email protected]5fe0f8742013-11-29 01:04:591152def _CheckCygwinShell(input_api, output_api):
1153 source_file_filter = lambda x: input_api.FilterSourceFile(
1154 x, white_list=(r'.+\.(gyp|gypi)$',))
1155 cygwin_shell = []
1156
1157 for f in input_api.AffectedSourceFiles(source_file_filter):
1158 for linenum, line in f.ChangedContents():
1159 if 'msvs_cygwin_shell' in line:
1160 cygwin_shell.append(f.LocalPath())
1161 break
1162
1163 if cygwin_shell:
1164 return [output_api.PresubmitError(
1165 'These files should not use msvs_cygwin_shell (the default is 0):',
1166 items=cygwin_shell)]
1167 return []
1168
[email protected]85218562013-11-22 07:41:401169
[email protected]999261d2014-03-03 20:08:081170def _CheckUserActionUpdate(input_api, output_api):
1171 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521172 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081173 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521174 # If actions.xml is already included in the changelist, the PRESUBMIT
1175 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081176 return []
1177
[email protected]999261d2014-03-03 20:08:081178 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1179 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521180 current_actions = None
[email protected]999261d2014-03-03 20:08:081181 for f in input_api.AffectedFiles(file_filter=file_filter):
1182 for line_num, line in f.ChangedContents():
1183 match = input_api.re.search(action_re, line)
1184 if match:
[email protected]2f92dec2014-03-07 19:21:521185 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1186 # loaded only once.
1187 if not current_actions:
1188 with open('tools/metrics/actions/actions.xml') as actions_f:
1189 current_actions = actions_f.read()
1190 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081191 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521192 action = 'name="{0}"'.format(action_name)
1193 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081194 return [output_api.PresubmitPromptWarning(
1195 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521196 'tools/metrics/actions/actions.xml. Please run '
1197 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081198 % (f.LocalPath(), line_num, action_name))]
1199 return []
1200
1201
[email protected]99171a92014-06-03 08:44:471202def _GetJSONParseError(input_api, filename, eat_comments=True):
1203 try:
1204 contents = input_api.ReadFile(filename)
1205 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131206 import sys
1207 original_sys_path = sys.path
1208 try:
1209 sys.path = sys.path + [input_api.os_path.join(
1210 input_api.PresubmitLocalPath(),
1211 'tools', 'json_comment_eater')]
1212 import json_comment_eater
1213 finally:
1214 sys.path = original_sys_path
1215 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471216
1217 input_api.json.loads(contents)
1218 except ValueError as e:
1219 return e
1220 return None
1221
1222
1223def _GetIDLParseError(input_api, filename):
1224 try:
1225 contents = input_api.ReadFile(filename)
1226 idl_schema = input_api.os_path.join(
1227 input_api.PresubmitLocalPath(),
1228 'tools', 'json_schema_compiler', 'idl_schema.py')
1229 process = input_api.subprocess.Popen(
1230 [input_api.python_executable, idl_schema],
1231 stdin=input_api.subprocess.PIPE,
1232 stdout=input_api.subprocess.PIPE,
1233 stderr=input_api.subprocess.PIPE,
1234 universal_newlines=True)
1235 (_, error) = process.communicate(input=contents)
1236 return error or None
1237 except ValueError as e:
1238 return e
1239
1240
1241def _CheckParseErrors(input_api, output_api):
1242 """Check that IDL and JSON files do not contain syntax errors."""
1243 actions = {
1244 '.idl': _GetIDLParseError,
1245 '.json': _GetJSONParseError,
1246 }
1247 # These paths contain test data and other known invalid JSON files.
1248 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491249 r'test[\\\/]data[\\\/]',
1250 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471251 ]
1252 # Most JSON files are preprocessed and support comments, but these do not.
1253 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491254 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471255 ]
1256 # Only run IDL checker on files in these directories.
1257 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491258 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1259 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471260 ]
1261
1262 def get_action(affected_file):
1263 filename = affected_file.LocalPath()
1264 return actions.get(input_api.os_path.splitext(filename)[1])
1265
1266 def MatchesFile(patterns, path):
1267 for pattern in patterns:
1268 if input_api.re.search(pattern, path):
1269 return True
1270 return False
1271
1272 def FilterFile(affected_file):
1273 action = get_action(affected_file)
1274 if not action:
1275 return False
1276 path = affected_file.LocalPath()
1277
1278 if MatchesFile(excluded_patterns, path):
1279 return False
1280
1281 if (action == _GetIDLParseError and
1282 not MatchesFile(idl_included_patterns, path)):
1283 return False
1284 return True
1285
1286 results = []
1287 for affected_file in input_api.AffectedFiles(
1288 file_filter=FilterFile, include_deletes=False):
1289 action = get_action(affected_file)
1290 kwargs = {}
1291 if (action == _GetJSONParseError and
1292 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1293 kwargs['eat_comments'] = False
1294 parse_error = action(input_api,
1295 affected_file.AbsoluteLocalPath(),
1296 **kwargs)
1297 if parse_error:
1298 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1299 (affected_file.LocalPath(), parse_error)))
1300 return results
1301
1302
[email protected]760deea2013-12-10 19:33:491303def _CheckJavaStyle(input_api, output_api):
1304 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471305 import sys
[email protected]760deea2013-12-10 19:33:491306 original_sys_path = sys.path
1307 try:
1308 sys.path = sys.path + [input_api.os_path.join(
1309 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1310 import checkstyle
1311 finally:
1312 # Restore sys.path to what it was before.
1313 sys.path = original_sys_path
1314
1315 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091316 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511317 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491318
1319
dskiba88634f4e2015-08-14 23:03:291320def _CheckAndroidToastUsage(input_api, output_api):
1321 """Checks that code uses org.chromium.ui.widget.Toast instead of
1322 android.widget.Toast (Chromium Toast doesn't force hardware
1323 acceleration on low-end devices, saving memory).
1324 """
1325 toast_import_pattern = input_api.re.compile(
1326 r'^import android\.widget\.Toast;$')
1327
1328 errors = []
1329
1330 sources = lambda affected_file: input_api.FilterSourceFile(
1331 affected_file,
1332 black_list=(_EXCLUDED_PATHS +
1333 _TEST_CODE_EXCLUDED_PATHS +
1334 input_api.DEFAULT_BLACK_LIST +
1335 (r'^chromecast[\\\/].*',
1336 r'^remoting[\\\/].*')),
1337 white_list=(r'.*\.java$',))
1338
1339 for f in input_api.AffectedSourceFiles(sources):
1340 for line_num, line in f.ChangedContents():
1341 if toast_import_pattern.search(line):
1342 errors.append("%s:%d" % (f.LocalPath(), line_num))
1343
1344 results = []
1345
1346 if errors:
1347 results.append(output_api.PresubmitError(
1348 'android.widget.Toast usage is detected. Android toasts use hardware'
1349 ' acceleration, and can be\ncostly on low-end devices. Please use'
1350 ' org.chromium.ui.widget.Toast instead.\n'
1351 'Contact [email protected] if you have any questions.',
1352 errors))
1353
1354 return results
1355
1356
dgnaa68d5e2015-06-10 10:08:221357def _CheckAndroidCrLogUsage(input_api, output_api):
1358 """Checks that new logs using org.chromium.base.Log:
1359 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511360 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221361 """
1362 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121363 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1364 class_in_base_pattern = input_api.re.compile(
1365 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1366 has_some_log_import_pattern = input_api.re.compile(
1367 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221368 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121369 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221370 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511371 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221372 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221373
Vincent Scheib16d7b272015-09-15 18:09:071374 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221375 'or contact [email protected] for more info.')
1376 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
dgn87d9fb62015-06-12 09:15:121377
dgnaa68d5e2015-06-10 10:08:221378 tag_decl_errors = []
1379 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121380 tag_errors = []
dgn38736db2015-09-18 19:20:511381 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121382 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221383
1384 for f in input_api.AffectedSourceFiles(sources):
1385 file_content = input_api.ReadFile(f)
1386 has_modified_logs = False
1387
1388 # Per line checks
dgn87d9fb62015-06-12 09:15:121389 if (cr_log_import_pattern.search(file_content) or
1390 (class_in_base_pattern.search(file_content) and
1391 not has_some_log_import_pattern.search(file_content))):
1392 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221393 for line_num, line in f.ChangedContents():
1394
1395 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121396 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221397 if match:
1398 has_modified_logs = True
1399
1400 # Make sure it uses "TAG"
1401 if not match.group('tag') == 'TAG':
1402 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121403 else:
1404 # Report non cr Log function calls in changed lines
1405 for line_num, line in f.ChangedContents():
1406 if log_call_pattern.search(line):
1407 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221408
1409 # Per file checks
1410 if has_modified_logs:
1411 # Make sure the tag is using the "cr" prefix and is not too long
1412 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511413 tag_name = match.group('name') if match else None
1414 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221415 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511416 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221417 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511418 elif '.' in tag_name:
1419 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221420
1421 results = []
1422 if tag_decl_errors:
1423 results.append(output_api.PresubmitPromptWarning(
1424 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511425 '"private static final String TAG = "<package tag>".\n'
1426 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221427 tag_decl_errors))
1428
1429 if tag_length_errors:
1430 results.append(output_api.PresubmitError(
1431 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511432 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221433 tag_length_errors))
1434
1435 if tag_errors:
1436 results.append(output_api.PresubmitPromptWarning(
1437 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1438 tag_errors))
1439
dgn87d9fb62015-06-12 09:15:121440 if util_log_errors:
dgn4401aa52015-04-29 16:26:171441 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121442 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1443 util_log_errors))
1444
dgn38736db2015-09-18 19:20:511445 if tag_with_dot_errors:
1446 results.append(output_api.PresubmitPromptWarning(
1447 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1448 tag_with_dot_errors))
1449
dgn4401aa52015-04-29 16:26:171450 return results
1451
1452
agrieve7b6479d82015-10-07 14:24:221453def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1454 """Checks if MDPI assets are placed in a correct directory."""
1455 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1456 ('/res/drawable/' in f.LocalPath() or
1457 '/res/drawable-ldrtl/' in f.LocalPath()))
1458 errors = []
1459 for f in input_api.AffectedFiles(include_deletes=False,
1460 file_filter=file_filter):
1461 errors.append(' %s' % f.LocalPath())
1462
1463 results = []
1464 if errors:
1465 results.append(output_api.PresubmitError(
1466 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1467 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1468 '/res/drawable-ldrtl/.\n'
1469 'Contact [email protected] if you have questions.', errors))
1470 return results
1471
1472
mnaganov9b9b1fe82014-12-11 16:30:361473def _CheckForCopyrightedCode(input_api, output_api):
1474 """Verifies that newly added code doesn't contain copyrighted material
1475 and is properly licensed under the standard Chromium license.
1476
1477 As there can be false positives, we maintain a whitelist file. This check
1478 also verifies that the whitelist file is up to date.
1479 """
1480 import sys
1481 original_sys_path = sys.path
1482 try:
1483 sys.path = sys.path + [input_api.os_path.join(
mnaganovf771be4a2015-06-12 18:13:221484 input_api.PresubmitLocalPath(), 'tools')]
1485 from copyright_scanner import copyright_scanner
mnaganov9b9b1fe82014-12-11 16:30:361486 finally:
1487 # Restore sys.path to what it was before.
1488 sys.path = original_sys_path
1489
1490 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1491
1492
glidere61efad2015-02-18 17:39:431493def _CheckSingletonInHeaders(input_api, output_api):
1494 """Checks to make sure no header files have |Singleton<|."""
1495 def FileFilter(affected_file):
1496 # It's ok for base/memory/singleton.h to have |Singleton<|.
1497 black_list = (_EXCLUDED_PATHS +
1498 input_api.DEFAULT_BLACK_LIST +
1499 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1500 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1501
sergeyu34d21222015-09-16 00:11:441502 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431503 files = []
1504 for f in input_api.AffectedSourceFiles(FileFilter):
1505 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1506 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1507 contents = input_api.ReadFile(f)
1508 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241509 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431510 pattern.search(line)):
1511 files.append(f)
1512 break
1513
1514 if files:
1515 return [ output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441516 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431517 'Please move them to an appropriate source file so that the ' +
1518 'template gets instantiated in a single compilation unit.',
1519 files) ]
1520 return []
1521
1522
dbeam3aa38392015-10-16 21:38:031523def _CheckBaseMacrosInHeaders(input_api, output_api):
1524 """Check for base/macros.h if DISALLOW_* macro is used."""
1525
1526 disallows = ('DISALLOW_ASSIGN', 'DISALLOW_COPY', 'DISALLOW_EVIL')
1527 macros = '#include "base/macros.h"'
1528 basictypes = '#include "base/basictypes.h"'
1529
1530 files = []
1531 for f in input_api.AffectedSourceFiles(None):
1532 if not f.LocalPath().endswith('.h'):
1533 continue
1534 for line_num, line in f.ChangedContents():
oysteinec430ad42015-10-22 20:55:241535 if line.lstrip().startswith('//'): # Strip C++ comment.
1536 continue
dbeam3aa38392015-10-16 21:38:031537 if any(d in line for d in disallows):
1538 contents = input_api.ReadFile(f)
1539 if not (macros in contents or basictypes in contents):
1540 files.append(f)
1541 break
1542
1543 msg = ('The following files appear to be using DISALLOW_* macros.\n'
1544 'Please #include "base/macros.h" in them.')
1545 return [output_api.PresubmitError(msg, files)] if files else []
1546
1547
[email protected]fd20b902014-05-09 02:14:531548_DEPRECATED_CSS = [
1549 # Values
1550 ( "-webkit-box", "flex" ),
1551 ( "-webkit-inline-box", "inline-flex" ),
1552 ( "-webkit-flex", "flex" ),
1553 ( "-webkit-inline-flex", "inline-flex" ),
1554 ( "-webkit-min-content", "min-content" ),
1555 ( "-webkit-max-content", "max-content" ),
1556
1557 # Properties
1558 ( "-webkit-background-clip", "background-clip" ),
1559 ( "-webkit-background-origin", "background-origin" ),
1560 ( "-webkit-background-size", "background-size" ),
1561 ( "-webkit-box-shadow", "box-shadow" ),
1562
1563 # Functions
1564 ( "-webkit-gradient", "gradient" ),
1565 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1566 ( "-webkit-linear-gradient", "linear-gradient" ),
1567 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1568 ( "-webkit-radial-gradient", "radial-gradient" ),
1569 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1570]
1571
1572def _CheckNoDeprecatedCSS(input_api, output_api):
1573 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251574 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341575 documentation and iOS CSS for dom distiller
1576 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251577 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531578 results = []
dbeam070cfe62014-10-22 06:44:021579 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251580 black_list = (_EXCLUDED_PATHS +
1581 _TEST_CODE_EXCLUDED_PATHS +
1582 input_api.DEFAULT_BLACK_LIST +
1583 (r"^chrome/common/extensions/docs",
1584 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341585 r"^components/dom_distiller/core/css/distilledpage_ios.css",
[email protected]9a48e3f82014-05-22 00:06:251586 r"^native_client_sdk"))
1587 file_filter = lambda f: input_api.FilterSourceFile(
1588 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531589 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1590 for line_num, line in fpath.ChangedContents():
1591 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021592 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531593 results.append(output_api.PresubmitError(
1594 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1595 (fpath.LocalPath(), line_num, deprecated_value, value)))
1596 return results
1597
mohan.reddyf21db962014-10-16 12:26:471598
dbeam070cfe62014-10-22 06:44:021599_DEPRECATED_JS = [
1600 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1601 ( "__defineGetter__", "Object.defineProperty" ),
1602 ( "__defineSetter__", "Object.defineProperty" ),
1603]
1604
1605def _CheckNoDeprecatedJS(input_api, output_api):
1606 """Make sure that we don't use deprecated JS in Chrome code."""
1607 results = []
1608 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1609 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1610 input_api.DEFAULT_BLACK_LIST)
1611 file_filter = lambda f: input_api.FilterSourceFile(
1612 f, white_list=file_inclusion_pattern, black_list=black_list)
1613 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1614 for lnum, line in fpath.ChangedContents():
1615 for (deprecated, replacement) in _DEPRECATED_JS:
1616 if deprecated in line:
1617 results.append(output_api.PresubmitError(
1618 "%s:%d: Use of deprecated JS %s, use %s instead" %
1619 (fpath.LocalPath(), lnum, deprecated, replacement)))
1620 return results
1621
1622
dgnaa68d5e2015-06-10 10:08:221623def _AndroidSpecificOnUploadChecks(input_api, output_api):
1624 """Groups checks that target android code."""
1625 results = []
dgnaa68d5e2015-06-10 10:08:221626 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:221627 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:291628 results.extend(_CheckAndroidToastUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221629 return results
1630
1631
[email protected]22c9bd72011-03-27 16:47:391632def _CommonChecks(input_api, output_api):
1633 """Checks common to both upload and commit."""
1634 results = []
1635 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381636 input_api, output_api,
1637 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461638 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191639 results.extend(
[email protected]760deea2013-12-10 19:33:491640 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541641 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181642 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221643 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441644 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591645 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061646 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121647 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181648 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221649 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491650 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271651 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031652 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491653 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441654 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271655 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541656 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441657 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461658 # TODO(danakj): Remove this when base/move.h is removed.
1659 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551660 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041661 results.extend(
1662 input_api.canned_checks.CheckChangeHasNoTabs(
1663 input_api,
1664 output_api,
1665 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401666 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161667 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591668 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081669 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531670 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021671 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471672 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041673 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361674 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231675 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431676 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam3aa38392015-10-16 21:38:031677 results.extend(_CheckBaseMacrosInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241678
1679 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1680 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1681 input_api, output_api,
1682 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381683 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391684 return results
[email protected]1f7b4172010-01-28 01:17:341685
[email protected]b337cb5b2011-01-23 21:24:051686
[email protected]66daa702011-05-28 14:41:461687def _CheckAuthorizedAuthor(input_api, output_api):
1688 """For non-googler/chromites committers, verify the author's email address is
1689 in AUTHORS.
1690 """
[email protected]9bb9cb82011-06-13 20:43:011691 # TODO(maruel): Add it to input_api?
1692 import fnmatch
1693
[email protected]66daa702011-05-28 14:41:461694 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011695 if not author:
1696 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461697 return []
[email protected]c99663292011-05-31 19:46:081698 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461699 input_api.PresubmitLocalPath(), 'AUTHORS')
1700 valid_authors = (
1701 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1702 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181703 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441704 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231705 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461706 return [output_api.PresubmitPromptWarning(
1707 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1708 '\n'
1709 'http://www.chromium.org/developers/contributing-code and read the '
1710 '"Legal" section\n'
1711 'If you are a chromite, verify the contributor signed the CLA.') %
1712 author)]
1713 return []
1714
1715
[email protected]b8079ae4a2012-12-05 19:56:491716def _CheckPatchFiles(input_api, output_api):
1717 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1718 if f.LocalPath().endswith(('.orig', '.rej'))]
1719 if problems:
1720 return [output_api.PresubmitError(
1721 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031722 else:
1723 return []
[email protected]b8079ae4a2012-12-05 19:56:491724
1725
[email protected]b00342e7f2013-03-26 16:21:541726def _DidYouMeanOSMacro(bad_macro):
1727 try:
1728 return {'A': 'OS_ANDROID',
1729 'B': 'OS_BSD',
1730 'C': 'OS_CHROMEOS',
1731 'F': 'OS_FREEBSD',
1732 'L': 'OS_LINUX',
1733 'M': 'OS_MACOSX',
1734 'N': 'OS_NACL',
1735 'O': 'OS_OPENBSD',
1736 'P': 'OS_POSIX',
1737 'S': 'OS_SOLARIS',
1738 'W': 'OS_WIN'}[bad_macro[3].upper()]
1739 except KeyError:
1740 return ''
1741
1742
1743def _CheckForInvalidOSMacrosInFile(input_api, f):
1744 """Check for sensible looking, totally invalid OS macros."""
1745 preprocessor_statement = input_api.re.compile(r'^\s*#')
1746 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1747 results = []
1748 for lnum, line in f.ChangedContents():
1749 if preprocessor_statement.search(line):
1750 for match in os_macro.finditer(line):
1751 if not match.group(1) in _VALID_OS_MACROS:
1752 good = _DidYouMeanOSMacro(match.group(1))
1753 did_you_mean = ' (did you mean %s?)' % good if good else ''
1754 results.append(' %s:%d %s%s' % (f.LocalPath(),
1755 lnum,
1756 match.group(1),
1757 did_you_mean))
1758 return results
1759
1760
1761def _CheckForInvalidOSMacros(input_api, output_api):
1762 """Check all affected files for invalid OS macros."""
1763 bad_macros = []
1764 for f in input_api.AffectedFiles():
1765 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1766 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1767
1768 if not bad_macros:
1769 return []
1770
1771 return [output_api.PresubmitError(
1772 'Possibly invalid OS macro[s] found. Please fix your code\n'
1773 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1774
lliabraa35bab3932014-10-01 12:16:441775
1776def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1777 """Check all affected files for invalid "if defined" macros."""
1778 ALWAYS_DEFINED_MACROS = (
1779 "TARGET_CPU_PPC",
1780 "TARGET_CPU_PPC64",
1781 "TARGET_CPU_68K",
1782 "TARGET_CPU_X86",
1783 "TARGET_CPU_ARM",
1784 "TARGET_CPU_MIPS",
1785 "TARGET_CPU_SPARC",
1786 "TARGET_CPU_ALPHA",
1787 "TARGET_IPHONE_SIMULATOR",
1788 "TARGET_OS_EMBEDDED",
1789 "TARGET_OS_IPHONE",
1790 "TARGET_OS_MAC",
1791 "TARGET_OS_UNIX",
1792 "TARGET_OS_WIN32",
1793 )
1794 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1795 results = []
1796 for lnum, line in f.ChangedContents():
1797 for match in ifdef_macro.finditer(line):
1798 if match.group(1) in ALWAYS_DEFINED_MACROS:
1799 always_defined = ' %s is always defined. ' % match.group(1)
1800 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1801 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1802 lnum,
1803 always_defined,
1804 did_you_mean))
1805 return results
1806
1807
1808def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1809 """Check all affected files for invalid "if defined" macros."""
1810 bad_macros = []
1811 for f in input_api.AffectedFiles():
1812 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1813 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1814
1815 if not bad_macros:
1816 return []
1817
1818 return [output_api.PresubmitError(
1819 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1820 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1821 bad_macros)]
1822
1823
danakj3c84d0c2014-10-06 15:35:461824def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1825 """Check all affected files for using side effects of Pass."""
1826 errors = []
1827 for f in input_api.AffectedFiles():
1828 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1829 for lnum, line in f.ChangedContents():
1830 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471831 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461832 errors.append(output_api.PresubmitError(
1833 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1834 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1835 return errors
1836
1837
mlamouria82272622014-09-16 18:45:041838def _CheckForIPCRules(input_api, output_api):
1839 """Check for same IPC rules described in
1840 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1841 """
1842 base_pattern = r'IPC_ENUM_TRAITS\('
1843 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1844 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1845
1846 problems = []
1847 for f in input_api.AffectedSourceFiles(None):
1848 local_path = f.LocalPath()
1849 if not local_path.endswith('.h'):
1850 continue
1851 for line_number, line in f.ChangedContents():
1852 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1853 problems.append(
1854 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1855
1856 if problems:
1857 return [output_api.PresubmitPromptWarning(
1858 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1859 else:
1860 return []
1861
[email protected]b00342e7f2013-03-26 16:21:541862
mostynbb639aca52015-01-07 20:31:231863def _CheckForWindowsLineEndings(input_api, output_api):
1864 """Check source code and known ascii text files for Windows style line
1865 endings.
1866 """
earthdok1b5e0ee2015-03-10 15:19:101867 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231868
1869 file_inclusion_pattern = (
1870 known_text_files,
1871 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1872 )
1873
1874 filter = lambda f: input_api.FilterSourceFile(
1875 f, white_list=file_inclusion_pattern, black_list=None)
1876 files = [f.LocalPath() for f in
1877 input_api.AffectedSourceFiles(filter)]
1878
1879 problems = []
1880
1881 for file in files:
1882 fp = open(file, 'r')
1883 for line in fp:
1884 if line.endswith('\r\n'):
1885 problems.append(file)
1886 break
1887 fp.close()
1888
1889 if problems:
1890 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1891 'these files to contain Windows style line endings?\n' +
1892 '\n'.join(problems))]
1893
1894 return []
1895
1896
[email protected]1f7b4172010-01-28 01:17:341897def CheckChangeOnUpload(input_api, output_api):
1898 results = []
1899 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471900 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171901 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281902 results.extend(
1903 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191904 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:221905 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541906 return results
[email protected]ca8d19842009-02-19 16:33:121907
1908
[email protected]1bfb8322014-04-23 01:02:411909def GetTryServerMasterForBot(bot):
1910 """Returns the Try Server master for the given bot.
1911
[email protected]0bb112362014-07-26 04:38:321912 It tries to guess the master from the bot name, but may still fail
1913 and return None. There is no longer a default master.
1914 """
1915 # Potentially ambiguous bot names are listed explicitly.
1916 master_map = {
[email protected]0bb112362014-07-26 04:38:321917 'chromium_presubmit': 'tryserver.chromium.linux',
1918 'blink_presubmit': 'tryserver.chromium.linux',
1919 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411920 }
[email protected]0bb112362014-07-26 04:38:321921 master = master_map.get(bot)
1922 if not master:
sergiyb37fd293f2015-02-26 06:55:011923 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321924 master = 'tryserver.chromium.linux'
1925 elif 'win' in bot:
1926 master = 'tryserver.chromium.win'
1927 elif 'mac' in bot or 'ios' in bot:
1928 master = 'tryserver.chromium.mac'
1929 return master
[email protected]1bfb8322014-04-23 01:02:411930
1931
Paweł Hajdan, Jr55083782014-12-19 20:32:561932def GetDefaultTryConfigs(bots):
1933 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011934 """
1935
Paweł Hajdan, Jr55083782014-12-19 20:32:561936 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411937
1938 # Build up the mapping from tryserver master to bot/test.
1939 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561940 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411941 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1942 return out
[email protected]38c6a512013-12-18 23:48:011943
1944
[email protected]ca8d19842009-02-19 16:33:121945def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541946 results = []
[email protected]1f7b4172010-01-28 01:17:341947 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511948 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1949 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1950 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541951 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271952 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341953 input_api,
1954 output_api,
[email protected]2fdd1f362013-01-16 03:56:031955 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271956
[email protected]3e4eb112011-01-18 03:29:541957 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1958 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411959 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1960 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541961 return results
[email protected]ca8d19842009-02-19 16:33:121962
1963
[email protected]7468ac522014-03-12 23:35:571964def GetPreferredTryMasters(project, change):
Paweł Hajdan, Jref2afd42015-01-07 15:59:521965 import json
sergiyb57a71e32015-06-03 18:44:001966 import os.path
1967 import platform
1968 import subprocess
smut3ef206e12015-03-20 09:30:001969
sergiyb57a71e32015-06-03 18:44:001970 cq_config_path = os.path.join(
1971 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
1972 # commit_queue.py below is a script in depot_tools directory, which has a
1973 # 'builders' command to retrieve a list of CQ builders from the CQ config.
1974 is_win = platform.system() == 'Windows'
1975 masters = json.loads(subprocess.check_output(
1976 ['commit_queue', 'builders', cq_config_path], shell=is_win))
[email protected]911753b2012-08-02 12:11:541977
sergiyb6092f742015-06-16 09:00:521978 try_config = {}
1979 for master in masters:
1980 try_config.setdefault(master, {})
1981 for builder in masters[master]:
sergiyb57a71e32015-06-03 18:44:001982 # Do not trigger presubmit builders, since they're likely to fail
1983 # (e.g. OWNERS checks before finished code review), and we're
1984 # running local presubmit anyway.
sergiyb6092f742015-06-16 09:00:521985 if 'presubmit' not in builder:
1986 try_config[master][builder] = ['defaulttests']
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321987
sergiyb6092f742015-06-16 09:00:521988 return try_config