blob: a84f3f90d7029a8c43c78c50d7ff1b69ce04a73c [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[\\\/].*",
19 r"^v8[\\\/].*",
20 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5321 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3422 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4223 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
[email protected]d2600602014-02-19 00:09:1924 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js"
[email protected]4306417642009-06-11 00:33:4025)
[email protected]ca8d19842009-02-19 16:33:1226
jochen9ea8fdbc2014-09-25 13:21:3527# The NetscapePlugIn library is excluded from pan-project as it will soon
28# be deleted together with the rest of the NPAPI and it's not worthwhile to
29# update the coding style until then.
[email protected]3de922f2013-12-20 13:27:3830_TESTRUNNER_PATHS = (
[email protected]de28fed2e2014-02-01 14:36:3231 r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
[email protected]3de922f2013-12-20 13:27:3832)
33
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
38# Regular expression that matches code only used for test binaries
39# (best effort).
40_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4941 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4442 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]6e04f8c2014-01-29 18:08:3243 r'.+_(api|browser|kif|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1244 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4445 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4946 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0547 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4948 r'content[\\\/]shell[\\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4449 # At request of folks maintaining this folder.
joaodasilva718f87672014-08-30 09:25:4950 r'chrome[\\\/]browser[\\\/]automation[\\\/].*',
[email protected]7b054982013-11-27 00:44:4751 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4952 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0853 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4954 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4455)
[email protected]ca8d19842009-02-19 16:33:1256
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
65 'Your #include order seems to be broken. Send mail to\n'
66 '[email protected] if this is not the case.')
67
68
[email protected]127f18ec2012-06-16 05:05:5969_BANNED_OBJC_FUNCTIONS = (
70 (
71 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2072 (
73 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5974 'prohibited. Please use CrTrackingArea instead.',
75 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
76 ),
77 False,
78 ),
79 (
[email protected]eaae1972014-04-16 04:17:2680 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2081 (
82 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5983 'instead.',
84 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
85 ),
86 False,
87 ),
88 (
89 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2090 (
91 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5992 'Please use |convertPoint:(point) fromView:nil| instead.',
93 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
94 ),
95 True,
96 ),
97 (
98 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2099 (
100 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59101 'Please use |convertPoint:(point) toView:nil| instead.',
102 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
103 ),
104 True,
105 ),
106 (
107 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20108 (
109 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59110 'Please use |convertRect:(point) fromView:nil| instead.',
111 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
112 ),
113 True,
114 ),
115 (
116 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20117 (
118 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59119 'Please use |convertRect:(point) toView:nil| instead.',
120 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
121 ),
122 True,
123 ),
124 (
125 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20126 (
127 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59128 'Please use |convertSize:(point) fromView:nil| instead.',
129 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
130 ),
131 True,
132 ),
133 (
134 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20135 (
136 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59137 'Please use |convertSize:(point) toView:nil| instead.',
138 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
139 ),
140 True,
141 ),
142)
143
144
145_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20146 # Make sure that gtest's FRIEND_TEST() macro is not used; the
147 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30148 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20149 (
150 'FRIEND_TEST(',
151 (
[email protected]e3c945502012-06-26 20:01:49152 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20153 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
154 ),
155 False,
[email protected]7345da02012-11-27 14:31:49156 (),
[email protected]23e6cbc2012-06-16 18:51:20157 ),
158 (
159 'ScopedAllowIO',
160 (
[email protected]e3c945502012-06-26 20:01:49161 'New code should not use ScopedAllowIO. Post a task to the blocking',
162 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20163 ),
[email protected]e3c945502012-06-26 20:01:49164 True,
[email protected]7345da02012-11-27 14:31:49165 (
thestig75844fdb2014-09-09 19:47:10166 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22167 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
alematee4016bb2014-11-12 17:38:51168 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
169 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09170 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
[email protected]de7d61ff2013-08-20 11:30:41171 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
172 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
jamesra03ae492014-10-03 04:26:48173 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
174 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01175 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
[email protected]1f52a572014-05-12 23:21:54176 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
Mitsuru Oshima756e484f2015-01-23 21:30:49177 r"^ui[\\\/]ozone[\\\/]platform[\\\/]dri[\\\/]native_display_delegate_proxy\.cc$",
[email protected]7345da02012-11-27 14:31:49178 ),
[email protected]23e6cbc2012-06-16 18:51:20179 ),
[email protected]52657f62013-05-20 05:30:31180 (
181 'SkRefPtr',
182 (
183 'The use of SkRefPtr is prohibited. ',
184 'Please use skia::RefPtr instead.'
185 ),
186 True,
187 (),
188 ),
189 (
190 'SkAutoRef',
191 (
192 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
193 'Please use skia::RefPtr instead.'
194 ),
195 True,
196 (),
197 ),
198 (
199 'SkAutoTUnref',
200 (
201 'The use of SkAutoTUnref is dangerous because it implicitly ',
202 'converts to a raw pointer. Please use skia::RefPtr instead.'
203 ),
204 True,
205 (),
206 ),
207 (
208 'SkAutoUnref',
209 (
210 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
211 'because it implicitly converts to a raw pointer. ',
212 'Please use skia::RefPtr instead.'
213 ),
214 True,
215 (),
216 ),
[email protected]d89eec82013-12-03 14:10:59217 (
218 r'/HANDLE_EINTR\(.*close',
219 (
220 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
221 'descriptor will be closed, and it is incorrect to retry the close.',
222 'Either call close directly and ignore its return value, or wrap close',
223 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
224 ),
225 True,
226 (),
227 ),
228 (
229 r'/IGNORE_EINTR\((?!.*close)',
230 (
231 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
232 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
233 ),
234 True,
235 (
236 # Files that #define IGNORE_EINTR.
237 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
238 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
239 ),
240 ),
[email protected]ec5b3f02014-04-04 18:43:43241 (
242 r'/v8::Extension\(',
243 (
244 'Do not introduce new v8::Extensions into the code base, use',
245 'gin::Wrappable instead. See http://crbug.com/334679',
246 ),
247 True,
[email protected]f55c90ee62014-04-12 00:50:03248 (
joaodasilva718f87672014-08-30 09:25:49249 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03250 ),
[email protected]ec5b3f02014-04-04 18:43:43251 ),
[email protected]127f18ec2012-06-16 05:05:59252)
253
mlamouria82272622014-09-16 18:45:04254_IPC_ENUM_TRAITS_DEPRECATED = (
255 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
256 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
257
[email protected]127f18ec2012-06-16 05:05:59258
[email protected]b00342e7f2013-03-26 16:21:54259_VALID_OS_MACROS = (
260 # Please keep sorted.
261 'OS_ANDROID',
[email protected]f4440b42014-03-19 05:47:01262 'OS_ANDROID_HOST',
[email protected]b00342e7f2013-03-26 16:21:54263 'OS_BSD',
264 'OS_CAT', # For testing.
265 'OS_CHROMEOS',
266 'OS_FREEBSD',
267 'OS_IOS',
268 'OS_LINUX',
269 'OS_MACOSX',
270 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21271 'OS_NACL_NONSFI',
272 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54273 'OS_OPENBSD',
274 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37275 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54276 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54277 'OS_WIN',
278)
279
280
[email protected]55459852011-08-10 15:17:19281def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
282 """Attempts to prevent use of functions intended only for testing in
283 non-testing code. For now this is just a best-effort implementation
284 that ignores header files and may have some false positives. A
285 better implementation would probably need a proper C++ parser.
286 """
287 # We only scan .cc files and the like, as the declaration of
288 # for-testing functions in header files are hard to distinguish from
289 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44290 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19291
[email protected]23501822014-05-14 02:06:09292 base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?'
[email protected]55459852011-08-10 15:17:19293 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09294 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19295 exclusion_pattern = input_api.re.compile(
296 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
297 base_function_pattern, base_function_pattern))
298
299 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44300 black_list = (_EXCLUDED_PATHS +
301 _TEST_CODE_EXCLUDED_PATHS +
302 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19303 return input_api.FilterSourceFile(
304 affected_file,
305 white_list=(file_inclusion_pattern, ),
306 black_list=black_list)
307
308 problems = []
309 for f in input_api.AffectedSourceFiles(FilterFile):
310 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24311 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03312 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46313 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03314 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19315 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03316 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19317
318 if problems:
[email protected]f7051d52013-04-02 18:31:42319 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03320 else:
321 return []
[email protected]55459852011-08-10 15:17:19322
323
[email protected]10689ca2011-09-02 02:31:54324def _CheckNoIOStreamInHeaders(input_api, output_api):
325 """Checks to make sure no .h files include <iostream>."""
326 files = []
327 pattern = input_api.re.compile(r'^#include\s*<iostream>',
328 input_api.re.MULTILINE)
329 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
330 if not f.LocalPath().endswith('.h'):
331 continue
332 contents = input_api.ReadFile(f)
333 if pattern.search(contents):
334 files.append(f)
335
336 if len(files):
337 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06338 'Do not #include <iostream> in header files, since it inserts static '
339 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54340 '#include <ostream>. See http://crbug.com/94794',
341 files) ]
342 return []
343
344
[email protected]72df4e782012-06-21 16:28:18345def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
346 """Checks to make sure no source files use UNIT_TEST"""
347 problems = []
348 for f in input_api.AffectedFiles():
349 if (not f.LocalPath().endswith(('.cc', '.mm'))):
350 continue
351
352 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04353 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18354 problems.append(' %s:%d' % (f.LocalPath(), line_num))
355
356 if not problems:
357 return []
358 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
359 '\n'.join(problems))]
360
361
mcasasb7440c282015-02-04 14:52:19362def _FindHistogramNameInLine(histogram_name, line):
363 """Tries to find a histogram name or prefix in a line."""
364 if not "affected-histogram" in line:
365 return histogram_name in line
366 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
367 # the histogram_name.
368 if not '"' in line:
369 return False
370 histogram_prefix = line.split('\"')[1]
371 return histogram_prefix in histogram_name
372
373
374def _CheckUmaHistogramChanges(input_api, output_api):
375 """Check that UMA histogram names in touched lines can still be found in other
376 lines of the patch or in histograms.xml. Note that this check would not catch
377 the reverse: changes in histograms.xml not matched in the code itself."""
378 touched_histograms = []
379 histograms_xml_modifications = []
380 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
381 for f in input_api.AffectedFiles():
382 # If histograms.xml itself is modified, keep the modified lines for later.
383 if f.LocalPath().endswith(('histograms.xml')):
384 histograms_xml_modifications = f.ChangedContents()
385 continue
386 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
387 continue
388 for line_num, line in f.ChangedContents():
389 found = pattern.search(line)
390 if found:
391 touched_histograms.append([found.group(1), f, line_num])
392
393 # Search for the touched histogram names in the local modifications to
394 # histograms.xml, and, if not found, on the base histograms.xml file.
395 unmatched_histograms = []
396 for histogram_info in touched_histograms:
397 histogram_name_found = False
398 for line_num, line in histograms_xml_modifications:
399 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
400 if histogram_name_found:
401 break
402 if not histogram_name_found:
403 unmatched_histograms.append(histogram_info)
404
405 problems = []
406 if unmatched_histograms:
407 with open('tools/metrics/histograms/histograms.xml') as histograms_xml:
408 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45409 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19410 histogram_name_found = False
411 for line in histograms_xml:
412 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
413 if histogram_name_found:
414 break
415 if not histogram_name_found:
416 problems.append(' [%s:%d] %s' %
417 (f.LocalPath(), line_num, histogram_name))
418
419 if not problems:
420 return []
421 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
422 'been modified and the associated histogram name has no match in either '
423 'metrics/histograms.xml or the modifications of it:', problems)]
424
425
[email protected]8ea5d4b2011-09-13 21:49:22426def _CheckNoNewWStrings(input_api, output_api):
427 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27428 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22429 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20430 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57431 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
432 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20433 continue
[email protected]8ea5d4b2011-09-13 21:49:22434
[email protected]a11dbe9b2012-08-07 01:32:58435 allowWString = False
[email protected]b5c24292011-11-28 14:38:20436 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58437 if 'presubmit: allow wstring' in line:
438 allowWString = True
439 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27440 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58441 allowWString = False
442 else:
443 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22444
[email protected]55463aa62011-10-12 00:48:27445 if not problems:
446 return []
447 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58448 ' If you are calling a cross-platform API that accepts a wstring, '
449 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27450 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22451
452
[email protected]2a8ac9c2011-10-19 17:20:44453def _CheckNoDEPSGIT(input_api, output_api):
454 """Make sure .DEPS.git is never modified manually."""
455 if any(f.LocalPath().endswith('.DEPS.git') for f in
456 input_api.AffectedFiles()):
457 return [output_api.PresubmitError(
458 'Never commit changes to .DEPS.git. This file is maintained by an\n'
459 'automated system based on what\'s in DEPS and your changes will be\n'
460 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34461 '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:44462 'for more information')]
463 return []
464
465
tandriief664692014-09-23 14:51:47466def _CheckValidHostsInDEPS(input_api, output_api):
467 """Checks that DEPS file deps are from allowed_hosts."""
468 # Run only if DEPS file has been modified to annoy fewer bystanders.
469 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
470 return []
471 # Outsource work to gclient verify
472 try:
473 input_api.subprocess.check_output(['gclient', 'verify'])
474 return []
475 except input_api.subprocess.CalledProcessError, error:
476 return [output_api.PresubmitError(
477 'DEPS file must have only git dependencies.',
478 long_text=error.output)]
479
480
[email protected]127f18ec2012-06-16 05:05:59481def _CheckNoBannedFunctions(input_api, output_api):
482 """Make sure that banned functions are not used."""
483 warnings = []
484 errors = []
485
486 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
487 for f in input_api.AffectedFiles(file_filter=file_filter):
488 for line_num, line in f.ChangedContents():
489 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26490 matched = False
491 if func_name[0:1] == '/':
492 regex = func_name[1:]
493 if input_api.re.search(regex, line):
494 matched = True
495 elif func_name in line:
496 matched = True
497 if matched:
[email protected]127f18ec2012-06-16 05:05:59498 problems = warnings;
499 if error:
500 problems = errors;
501 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
502 for message_line in message:
503 problems.append(' %s' % message_line)
504
505 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
506 for f in input_api.AffectedFiles(file_filter=file_filter):
507 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49508 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
509 def IsBlacklisted(affected_file, blacklist):
510 local_path = affected_file.LocalPath()
511 for item in blacklist:
512 if input_api.re.match(item, local_path):
513 return True
514 return False
515 if IsBlacklisted(f, excluded_paths):
516 continue
[email protected]d89eec82013-12-03 14:10:59517 matched = False
518 if func_name[0:1] == '/':
519 regex = func_name[1:]
520 if input_api.re.search(regex, line):
521 matched = True
522 elif func_name in line:
523 matched = True
524 if matched:
[email protected]127f18ec2012-06-16 05:05:59525 problems = warnings;
526 if error:
527 problems = errors;
528 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
529 for message_line in message:
530 problems.append(' %s' % message_line)
531
532 result = []
533 if (warnings):
534 result.append(output_api.PresubmitPromptWarning(
535 'Banned functions were used.\n' + '\n'.join(warnings)))
536 if (errors):
537 result.append(output_api.PresubmitError(
538 'Banned functions were used.\n' + '\n'.join(errors)))
539 return result
540
541
[email protected]6c063c62012-07-11 19:11:06542def _CheckNoPragmaOnce(input_api, output_api):
543 """Make sure that banned functions are not used."""
544 files = []
545 pattern = input_api.re.compile(r'^#pragma\s+once',
546 input_api.re.MULTILINE)
547 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
548 if not f.LocalPath().endswith('.h'):
549 continue
550 contents = input_api.ReadFile(f)
551 if pattern.search(contents):
552 files.append(f)
553
554 if files:
555 return [output_api.PresubmitError(
556 'Do not use #pragma once in header files.\n'
557 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
558 files)]
559 return []
560
[email protected]127f18ec2012-06-16 05:05:59561
[email protected]e7479052012-09-19 00:26:12562def _CheckNoTrinaryTrueFalse(input_api, output_api):
563 """Checks to make sure we don't introduce use of foo ? true : false."""
564 problems = []
565 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
566 for f in input_api.AffectedFiles():
567 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
568 continue
569
570 for line_num, line in f.ChangedContents():
571 if pattern.match(line):
572 problems.append(' %s:%d' % (f.LocalPath(), line_num))
573
574 if not problems:
575 return []
576 return [output_api.PresubmitPromptWarning(
577 'Please consider avoiding the "? true : false" pattern if possible.\n' +
578 '\n'.join(problems))]
579
580
[email protected]55f9f382012-07-31 11:02:18581def _CheckUnwantedDependencies(input_api, output_api):
582 """Runs checkdeps on #include statements added in this
583 change. Breaking - rules is an error, breaking ! rules is a
584 warning.
585 """
mohan.reddyf21db962014-10-16 12:26:47586 import sys
[email protected]55f9f382012-07-31 11:02:18587 # We need to wait until we have an input_api object and use this
588 # roundabout construct to import checkdeps because this file is
589 # eval-ed and thus doesn't have __file__.
590 original_sys_path = sys.path
591 try:
592 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47593 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18594 import checkdeps
595 from cpp_checker import CppChecker
596 from rules import Rule
597 finally:
598 # Restore sys.path to what it was before.
599 sys.path = original_sys_path
600
601 added_includes = []
602 for f in input_api.AffectedFiles():
603 if not CppChecker.IsCppFile(f.LocalPath()):
604 continue
605
606 changed_lines = [line for line_num, line in f.ChangedContents()]
607 added_includes.append([f.LocalPath(), changed_lines])
608
[email protected]26385172013-05-09 23:11:35609 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18610
611 error_descriptions = []
612 warning_descriptions = []
613 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
614 added_includes):
615 description_with_path = '%s\n %s' % (path, rule_description)
616 if rule_type == Rule.DISALLOW:
617 error_descriptions.append(description_with_path)
618 else:
619 warning_descriptions.append(description_with_path)
620
621 results = []
622 if error_descriptions:
623 results.append(output_api.PresubmitError(
624 'You added one or more #includes that violate checkdeps rules.',
625 error_descriptions))
626 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42627 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18628 'You added one or more #includes of files that are temporarily\n'
629 'allowed but being removed. Can you avoid introducing the\n'
630 '#include? See relevant DEPS file(s) for details and contacts.',
631 warning_descriptions))
632 return results
633
634
[email protected]fbcafe5a2012-08-08 15:31:22635def _CheckFilePermissions(input_api, output_api):
636 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15637 if input_api.platform == 'win32':
638 return []
mohan.reddyf21db962014-10-16 12:26:47639 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
640 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22641 for f in input_api.AffectedFiles():
642 args += ['--file', f.LocalPath()]
[email protected]f0d330f2014-01-30 01:44:34643 checkperms = input_api.subprocess.Popen(args,
644 stdout=input_api.subprocess.PIPE)
645 errors = checkperms.communicate()[0].strip()
[email protected]fbcafe5a2012-08-08 15:31:22646 if errors:
[email protected]f0d330f2014-01-30 01:44:34647 return [output_api.PresubmitError('checkperms.py failed.',
648 errors.splitlines())]
649 return []
[email protected]fbcafe5a2012-08-08 15:31:22650
651
[email protected]c8278b32012-10-30 20:35:49652def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
653 """Makes sure we don't include ui/aura/window_property.h
654 in header files.
655 """
656 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
657 errors = []
658 for f in input_api.AffectedFiles():
659 if not f.LocalPath().endswith('.h'):
660 continue
661 for line_num, line in f.ChangedContents():
662 if pattern.match(line):
663 errors.append(' %s:%d' % (f.LocalPath(), line_num))
664
665 results = []
666 if errors:
667 results.append(output_api.PresubmitError(
668 'Header files should not include ui/aura/window_property.h', errors))
669 return results
670
671
[email protected]cf9b78f2012-11-14 11:40:28672def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
673 """Checks that the lines in scope occur in the right order.
674
675 1. C system files in alphabetical order
676 2. C++ system files in alphabetical order
677 3. Project's .h files
678 """
679
680 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
681 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
682 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
683
684 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
685
686 state = C_SYSTEM_INCLUDES
687
688 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57689 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28690 problem_linenums = []
691 for line_num, line in scope:
692 if c_system_include_pattern.match(line):
693 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57694 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28695 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57696 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28697 elif cpp_system_include_pattern.match(line):
698 if state == C_SYSTEM_INCLUDES:
699 state = CPP_SYSTEM_INCLUDES
700 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57701 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28702 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57703 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28704 elif custom_include_pattern.match(line):
705 if state != CUSTOM_INCLUDES:
706 state = CUSTOM_INCLUDES
707 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57708 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28709 else:
710 problem_linenums.append(line_num)
711 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57712 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28713
714 warnings = []
[email protected]728b9bb2012-11-14 20:38:57715 for (line_num, previous_line_num) in problem_linenums:
716 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28717 warnings.append(' %s:%d' % (file_path, line_num))
718 return warnings
719
720
[email protected]ac294a12012-12-06 16:38:43721def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28722 """Checks the #include order for the given file f."""
723
[email protected]2299dcf2012-11-15 19:56:24724 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30725 # Exclude the following includes from the check:
726 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
727 # specific order.
728 # 2) <atlbase.h>, "build/build_config.h"
729 excluded_include_pattern = input_api.re.compile(
730 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24731 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33732 # Match the final or penultimate token if it is xxxtest so we can ignore it
733 # when considering the special first include.
734 test_file_tag_pattern = input_api.re.compile(
735 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11736 if_pattern = input_api.re.compile(
737 r'\s*#\s*(if|elif|else|endif|define|undef).*')
738 # Some files need specialized order of includes; exclude such files from this
739 # check.
740 uncheckable_includes_pattern = input_api.re.compile(
741 r'\s*#include '
742 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28743
744 contents = f.NewContents()
745 warnings = []
746 line_num = 0
747
[email protected]ac294a12012-12-06 16:38:43748 # Handle the special first include. If the first include file is
749 # some/path/file.h, the corresponding including file can be some/path/file.cc,
750 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
751 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33752 # If the included file is some/path/file_platform.h the including file could
753 # also be some/path/file_xxxtest_platform.h.
754 including_file_base_name = test_file_tag_pattern.sub(
755 '', input_api.os_path.basename(f.LocalPath()))
756
[email protected]ac294a12012-12-06 16:38:43757 for line in contents:
758 line_num += 1
759 if system_include_pattern.match(line):
760 # No special first include -> process the line again along with normal
761 # includes.
762 line_num -= 1
763 break
764 match = custom_include_pattern.match(line)
765 if match:
766 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33767 header_basename = test_file_tag_pattern.sub(
768 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
769
770 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24771 # No special first include -> process the line again along with normal
772 # includes.
773 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43774 break
[email protected]cf9b78f2012-11-14 11:40:28775
776 # Split into scopes: Each region between #if and #endif is its own scope.
777 scopes = []
778 current_scope = []
779 for line in contents[line_num:]:
780 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11781 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54782 continue
[email protected]2309b0fa02012-11-16 12:18:27783 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28784 scopes.append(current_scope)
785 current_scope = []
[email protected]962f117e2012-11-22 18:11:56786 elif ((system_include_pattern.match(line) or
787 custom_include_pattern.match(line)) and
788 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28789 current_scope.append((line_num, line))
790 scopes.append(current_scope)
791
792 for scope in scopes:
793 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
794 changed_linenums))
795 return warnings
796
797
798def _CheckIncludeOrder(input_api, output_api):
799 """Checks that the #include order is correct.
800
801 1. The corresponding header for source files.
802 2. C system files in alphabetical order
803 3. C++ system files in alphabetical order
804 4. Project's .h files in alphabetical order
805
[email protected]ac294a12012-12-06 16:38:43806 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
807 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28808 """
[email protected]e120b012014-08-15 19:08:35809 def FileFilterIncludeOrder(affected_file):
810 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
811 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28812
813 warnings = []
[email protected]e120b012014-08-15 19:08:35814 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
[email protected]ac294a12012-12-06 16:38:43815 if f.LocalPath().endswith(('.cc', '.h')):
816 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
817 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28818
819 results = []
820 if warnings:
[email protected]f7051d52013-04-02 18:31:42821 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53822 warnings))
[email protected]cf9b78f2012-11-14 11:40:28823 return results
824
825
[email protected]70ca77752012-11-20 03:45:03826def _CheckForVersionControlConflictsInFile(input_api, f):
827 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
828 errors = []
829 for line_num, line in f.ChangedContents():
830 if pattern.match(line):
831 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
832 return errors
833
834
835def _CheckForVersionControlConflicts(input_api, output_api):
836 """Usually this is not intentional and will cause a compile failure."""
837 errors = []
838 for f in input_api.AffectedFiles():
839 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
840
841 results = []
842 if errors:
843 results.append(output_api.PresubmitError(
844 'Version control conflict markers found, please resolve.', errors))
845 return results
846
847
[email protected]06e6d0ff2012-12-11 01:36:44848def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
849 def FilterFile(affected_file):
850 """Filter function for use with input_api.AffectedSourceFiles,
851 below. This filters out everything except non-test files from
852 top-level directories that generally speaking should not hard-code
853 service URLs (e.g. src/android_webview/, src/content/ and others).
854 """
855 return input_api.FilterSourceFile(
856 affected_file,
[email protected]78bb39d62012-12-11 15:11:56857 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44858 black_list=(_EXCLUDED_PATHS +
859 _TEST_CODE_EXCLUDED_PATHS +
860 input_api.DEFAULT_BLACK_LIST))
861
[email protected]de4f7d22013-05-23 14:27:46862 base_pattern = '"[^"]*google\.com[^"]*"'
863 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
864 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44865 problems = [] # items are (filename, line_number, line)
866 for f in input_api.AffectedSourceFiles(FilterFile):
867 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46868 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44869 problems.append((f.LocalPath(), line_num, line))
870
871 if problems:
[email protected]f7051d52013-04-02 18:31:42872 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44873 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58874 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44875 [' %s:%d: %s' % (
876 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03877 else:
878 return []
[email protected]06e6d0ff2012-12-11 01:36:44879
880
[email protected]d2530012013-01-25 16:39:27881def _CheckNoAbbreviationInPngFileName(input_api, output_api):
882 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31883 The native_client_sdk directory is excluded because it has auto-generated PNG
884 files for documentation.
[email protected]d2530012013-01-25 16:39:27885 """
[email protected]d2530012013-01-25 16:39:27886 errors = []
binji0dcdf342014-12-12 18:32:31887 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
888 black_list = (r'^native_client_sdk[\\\/]',)
889 file_filter = lambda f: input_api.FilterSourceFile(
890 f, white_list=white_list, black_list=black_list)
891 for f in input_api.AffectedFiles(include_deletes=False,
892 file_filter=file_filter):
893 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27894
895 results = []
896 if errors:
897 results.append(output_api.PresubmitError(
898 'The name of PNG files should not have abbreviations. \n'
899 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
900 'Contact [email protected] if you have questions.', errors))
901 return results
902
903
[email protected]14a6131c2014-01-08 01:15:41904def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08905 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41906 a set of DEPS entries that we should look up.
907
908 For a directory (rather than a specific filename) we fake a path to
909 a specific filename by adding /DEPS. This is chosen as a file that
910 will seldom or never be subject to per-file include_rules.
911 """
[email protected]2b438d62013-11-14 17:54:14912 # We ignore deps entries on auto-generated directories.
913 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08914
915 # This pattern grabs the path without basename in the first
916 # parentheses, and the basename (if present) in the second. It
917 # relies on the simple heuristic that if there is a basename it will
918 # be a header file ending in ".h".
919 pattern = re.compile(
920 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14921 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08922 for changed_line in changed_lines:
923 m = pattern.match(changed_line)
924 if m:
925 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14926 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41927 if m.group(2):
928 results.add('%s%s' % (path, m.group(2)))
929 else:
930 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08931 return results
932
933
[email protected]e871964c2013-05-13 14:14:55934def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
935 """When a dependency prefixed with + is added to a DEPS file, we
936 want to make sure that the change is reviewed by an OWNER of the
937 target file or directory, to avoid layering violations from being
938 introduced. This check verifies that this happens.
939 """
940 changed_lines = set()
941 for f in input_api.AffectedFiles():
942 filename = input_api.os_path.basename(f.LocalPath())
943 if filename == 'DEPS':
944 changed_lines |= set(line.strip()
945 for line_num, line
946 in f.ChangedContents())
947 if not changed_lines:
948 return []
949
[email protected]14a6131c2014-01-08 01:15:41950 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
951 changed_lines)
[email protected]e871964c2013-05-13 14:14:55952 if not virtual_depended_on_files:
953 return []
954
955 if input_api.is_committing:
956 if input_api.tbr:
957 return [output_api.PresubmitNotifyResult(
958 '--tbr was specified, skipping OWNERS check for DEPS additions')]
959 if not input_api.change.issue:
960 return [output_api.PresubmitError(
961 "DEPS approval by OWNERS check failed: this change has "
962 "no Rietveld issue number, so we can't check it for approvals.")]
963 output = output_api.PresubmitError
964 else:
965 output = output_api.PresubmitNotifyResult
966
967 owners_db = input_api.owners_db
968 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
969 input_api,
970 owners_db.email_regexp,
971 approval_needed=input_api.is_committing)
972
973 owner_email = owner_email or input_api.change.author_email
974
[email protected]de4f7d22013-05-23 14:27:46975 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:51976 if owner_email:
[email protected]de4f7d22013-05-23 14:27:46977 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:55978 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
979 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:41980
981 # We strip the /DEPS part that was added by
982 # _FilesToCheckForIncomingDeps to fake a path to a file in a
983 # directory.
984 def StripDeps(path):
985 start_deps = path.rfind('/DEPS')
986 if start_deps != -1:
987 return path[:start_deps]
988 else:
989 return path
990 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:55991 for path in missing_files]
992
993 if unapproved_dependencies:
994 output_list = [
[email protected]14a6131c2014-01-08 01:15:41995 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:55996 '\n '.join(sorted(unapproved_dependencies)))]
997 if not input_api.is_committing:
998 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
999 output_list.append(output(
1000 'Suggested missing target path OWNERS:\n %s' %
1001 '\n '.join(suggested_owners or [])))
1002 return output_list
1003
1004 return []
1005
1006
[email protected]85218562013-11-22 07:41:401007def _CheckSpamLogging(input_api, output_api):
1008 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1009 black_list = (_EXCLUDED_PATHS +
1010 _TEST_CODE_EXCLUDED_PATHS +
1011 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501012 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191013 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481014 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461015 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121016 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1017 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581018 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161019 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031020 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151021 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1022 r"^chromecast[\\\/]",
1023 r"^cloud_print[\\\/]",
[email protected]9056e732014-01-08 06:25:251024 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1025 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111026 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151027 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111028 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521029 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501030 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361031 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311032 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131033 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441034 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021035 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441036 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401037 source_file_filter = lambda x: input_api.FilterSourceFile(
1038 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1039
1040 log_info = []
1041 printf = []
1042
1043 for f in input_api.AffectedSourceFiles(source_file_filter):
1044 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471045 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401046 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471047 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131048 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371049
mohan.reddyf21db962014-10-16 12:26:471050 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371051 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471052 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401053 printf.append(f.LocalPath())
1054
1055 if log_info:
1056 return [output_api.PresubmitError(
1057 'These files spam the console log with LOG(INFO):',
1058 items=log_info)]
1059 if printf:
1060 return [output_api.PresubmitError(
1061 'These files spam the console log with printf/fprintf:',
1062 items=printf)]
1063 return []
1064
1065
[email protected]49aa76a2013-12-04 06:59:161066def _CheckForAnonymousVariables(input_api, output_api):
1067 """These types are all expected to hold locks while in scope and
1068 so should never be anonymous (which causes them to be immediately
1069 destroyed)."""
1070 they_who_must_be_named = [
1071 'base::AutoLock',
1072 'base::AutoReset',
1073 'base::AutoUnlock',
1074 'SkAutoAlphaRestore',
1075 'SkAutoBitmapShaderInstall',
1076 'SkAutoBlitterChoose',
1077 'SkAutoBounderCommit',
1078 'SkAutoCallProc',
1079 'SkAutoCanvasRestore',
1080 'SkAutoCommentBlock',
1081 'SkAutoDescriptor',
1082 'SkAutoDisableDirectionCheck',
1083 'SkAutoDisableOvalCheck',
1084 'SkAutoFree',
1085 'SkAutoGlyphCache',
1086 'SkAutoHDC',
1087 'SkAutoLockColors',
1088 'SkAutoLockPixels',
1089 'SkAutoMalloc',
1090 'SkAutoMaskFreeImage',
1091 'SkAutoMutexAcquire',
1092 'SkAutoPathBoundsUpdate',
1093 'SkAutoPDFRelease',
1094 'SkAutoRasterClipValidate',
1095 'SkAutoRef',
1096 'SkAutoTime',
1097 'SkAutoTrace',
1098 'SkAutoUnref',
1099 ]
1100 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1101 # bad: base::AutoLock(lock.get());
1102 # not bad: base::AutoLock lock(lock.get());
1103 bad_pattern = input_api.re.compile(anonymous)
1104 # good: new base::AutoLock(lock.get())
1105 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1106 errors = []
1107
1108 for f in input_api.AffectedFiles():
1109 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1110 continue
1111 for linenum, line in f.ChangedContents():
1112 if bad_pattern.search(line) and not good_pattern.search(line):
1113 errors.append('%s:%d' % (f.LocalPath(), linenum))
1114
1115 if errors:
1116 return [output_api.PresubmitError(
1117 'These lines create anonymous variables that need to be named:',
1118 items=errors)]
1119 return []
1120
1121
[email protected]5fe0f8742013-11-29 01:04:591122def _CheckCygwinShell(input_api, output_api):
1123 source_file_filter = lambda x: input_api.FilterSourceFile(
1124 x, white_list=(r'.+\.(gyp|gypi)$',))
1125 cygwin_shell = []
1126
1127 for f in input_api.AffectedSourceFiles(source_file_filter):
1128 for linenum, line in f.ChangedContents():
1129 if 'msvs_cygwin_shell' in line:
1130 cygwin_shell.append(f.LocalPath())
1131 break
1132
1133 if cygwin_shell:
1134 return [output_api.PresubmitError(
1135 'These files should not use msvs_cygwin_shell (the default is 0):',
1136 items=cygwin_shell)]
1137 return []
1138
[email protected]85218562013-11-22 07:41:401139
[email protected]999261d2014-03-03 20:08:081140def _CheckUserActionUpdate(input_api, output_api):
1141 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521142 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081143 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521144 # If actions.xml is already included in the changelist, the PRESUBMIT
1145 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081146 return []
1147
[email protected]999261d2014-03-03 20:08:081148 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1149 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521150 current_actions = None
[email protected]999261d2014-03-03 20:08:081151 for f in input_api.AffectedFiles(file_filter=file_filter):
1152 for line_num, line in f.ChangedContents():
1153 match = input_api.re.search(action_re, line)
1154 if match:
[email protected]2f92dec2014-03-07 19:21:521155 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1156 # loaded only once.
1157 if not current_actions:
1158 with open('tools/metrics/actions/actions.xml') as actions_f:
1159 current_actions = actions_f.read()
1160 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081161 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521162 action = 'name="{0}"'.format(action_name)
1163 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081164 return [output_api.PresubmitPromptWarning(
1165 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521166 'tools/metrics/actions/actions.xml. Please run '
1167 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081168 % (f.LocalPath(), line_num, action_name))]
1169 return []
1170
1171
[email protected]99171a92014-06-03 08:44:471172def _GetJSONParseError(input_api, filename, eat_comments=True):
1173 try:
1174 contents = input_api.ReadFile(filename)
1175 if eat_comments:
1176 json_comment_eater = input_api.os_path.join(
1177 input_api.PresubmitLocalPath(),
1178 'tools', 'json_comment_eater', 'json_comment_eater.py')
1179 process = input_api.subprocess.Popen(
1180 [input_api.python_executable, json_comment_eater],
1181 stdin=input_api.subprocess.PIPE,
1182 stdout=input_api.subprocess.PIPE,
1183 universal_newlines=True)
1184 (contents, _) = process.communicate(input=contents)
1185
1186 input_api.json.loads(contents)
1187 except ValueError as e:
1188 return e
1189 return None
1190
1191
1192def _GetIDLParseError(input_api, filename):
1193 try:
1194 contents = input_api.ReadFile(filename)
1195 idl_schema = input_api.os_path.join(
1196 input_api.PresubmitLocalPath(),
1197 'tools', 'json_schema_compiler', 'idl_schema.py')
1198 process = input_api.subprocess.Popen(
1199 [input_api.python_executable, idl_schema],
1200 stdin=input_api.subprocess.PIPE,
1201 stdout=input_api.subprocess.PIPE,
1202 stderr=input_api.subprocess.PIPE,
1203 universal_newlines=True)
1204 (_, error) = process.communicate(input=contents)
1205 return error or None
1206 except ValueError as e:
1207 return e
1208
1209
1210def _CheckParseErrors(input_api, output_api):
1211 """Check that IDL and JSON files do not contain syntax errors."""
1212 actions = {
1213 '.idl': _GetIDLParseError,
1214 '.json': _GetJSONParseError,
1215 }
1216 # These paths contain test data and other known invalid JSON files.
1217 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491218 r'test[\\\/]data[\\\/]',
1219 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471220 ]
1221 # Most JSON files are preprocessed and support comments, but these do not.
1222 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491223 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471224 ]
1225 # Only run IDL checker on files in these directories.
1226 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491227 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1228 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471229 ]
1230
1231 def get_action(affected_file):
1232 filename = affected_file.LocalPath()
1233 return actions.get(input_api.os_path.splitext(filename)[1])
1234
1235 def MatchesFile(patterns, path):
1236 for pattern in patterns:
1237 if input_api.re.search(pattern, path):
1238 return True
1239 return False
1240
1241 def FilterFile(affected_file):
1242 action = get_action(affected_file)
1243 if not action:
1244 return False
1245 path = affected_file.LocalPath()
1246
1247 if MatchesFile(excluded_patterns, path):
1248 return False
1249
1250 if (action == _GetIDLParseError and
1251 not MatchesFile(idl_included_patterns, path)):
1252 return False
1253 return True
1254
1255 results = []
1256 for affected_file in input_api.AffectedFiles(
1257 file_filter=FilterFile, include_deletes=False):
1258 action = get_action(affected_file)
1259 kwargs = {}
1260 if (action == _GetJSONParseError and
1261 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1262 kwargs['eat_comments'] = False
1263 parse_error = action(input_api,
1264 affected_file.AbsoluteLocalPath(),
1265 **kwargs)
1266 if parse_error:
1267 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1268 (affected_file.LocalPath(), parse_error)))
1269 return results
1270
1271
[email protected]760deea2013-12-10 19:33:491272def _CheckJavaStyle(input_api, output_api):
1273 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471274 import sys
[email protected]760deea2013-12-10 19:33:491275 original_sys_path = sys.path
1276 try:
1277 sys.path = sys.path + [input_api.os_path.join(
1278 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1279 import checkstyle
1280 finally:
1281 # Restore sys.path to what it was before.
1282 sys.path = original_sys_path
1283
1284 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091285 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511286 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491287
1288
mnaganov9b9b1fe82014-12-11 16:30:361289def _CheckForCopyrightedCode(input_api, output_api):
1290 """Verifies that newly added code doesn't contain copyrighted material
1291 and is properly licensed under the standard Chromium license.
1292
1293 As there can be false positives, we maintain a whitelist file. This check
1294 also verifies that the whitelist file is up to date.
1295 """
1296 import sys
1297 original_sys_path = sys.path
1298 try:
1299 sys.path = sys.path + [input_api.os_path.join(
1300 input_api.PresubmitLocalPath(), 'android_webview', 'tools')]
1301 import copyright_scanner
1302 finally:
1303 # Restore sys.path to what it was before.
1304 sys.path = original_sys_path
1305
1306 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1307
1308
glidere61efad2015-02-18 17:39:431309def _CheckSingletonInHeaders(input_api, output_api):
1310 """Checks to make sure no header files have |Singleton<|."""
1311 def FileFilter(affected_file):
1312 # It's ok for base/memory/singleton.h to have |Singleton<|.
1313 black_list = (_EXCLUDED_PATHS +
1314 input_api.DEFAULT_BLACK_LIST +
1315 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1316 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1317
1318 pattern = input_api.re.compile(r'(?<!class\s)Singleton\s*<')
1319 files = []
1320 for f in input_api.AffectedSourceFiles(FileFilter):
1321 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1322 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1323 contents = input_api.ReadFile(f)
1324 for line in contents.splitlines(False):
1325 if (not input_api.re.match(r'//', line) and # Strip C++ comment.
1326 pattern.search(line)):
1327 files.append(f)
1328 break
1329
1330 if files:
1331 return [ output_api.PresubmitError(
1332 'Found Singleton<T> in the following header files.\n' +
1333 'Please move them to an appropriate source file so that the ' +
1334 'template gets instantiated in a single compilation unit.',
1335 files) ]
1336 return []
1337
1338
[email protected]fd20b902014-05-09 02:14:531339_DEPRECATED_CSS = [
1340 # Values
1341 ( "-webkit-box", "flex" ),
1342 ( "-webkit-inline-box", "inline-flex" ),
1343 ( "-webkit-flex", "flex" ),
1344 ( "-webkit-inline-flex", "inline-flex" ),
1345 ( "-webkit-min-content", "min-content" ),
1346 ( "-webkit-max-content", "max-content" ),
1347
1348 # Properties
1349 ( "-webkit-background-clip", "background-clip" ),
1350 ( "-webkit-background-origin", "background-origin" ),
1351 ( "-webkit-background-size", "background-size" ),
1352 ( "-webkit-box-shadow", "box-shadow" ),
1353
1354 # Functions
1355 ( "-webkit-gradient", "gradient" ),
1356 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1357 ( "-webkit-linear-gradient", "linear-gradient" ),
1358 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1359 ( "-webkit-radial-gradient", "radial-gradient" ),
1360 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1361]
1362
1363def _CheckNoDeprecatedCSS(input_api, output_api):
1364 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251365 properties, functions or values. Our external
1366 documentation is ignored by the hooks as it
1367 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531368 results = []
dbeam070cfe62014-10-22 06:44:021369 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251370 black_list = (_EXCLUDED_PATHS +
1371 _TEST_CODE_EXCLUDED_PATHS +
1372 input_api.DEFAULT_BLACK_LIST +
1373 (r"^chrome/common/extensions/docs",
1374 r"^chrome/docs",
1375 r"^native_client_sdk"))
1376 file_filter = lambda f: input_api.FilterSourceFile(
1377 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531378 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1379 for line_num, line in fpath.ChangedContents():
1380 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021381 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531382 results.append(output_api.PresubmitError(
1383 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1384 (fpath.LocalPath(), line_num, deprecated_value, value)))
1385 return results
1386
mohan.reddyf21db962014-10-16 12:26:471387
dbeam070cfe62014-10-22 06:44:021388_DEPRECATED_JS = [
1389 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1390 ( "__defineGetter__", "Object.defineProperty" ),
1391 ( "__defineSetter__", "Object.defineProperty" ),
1392]
1393
1394def _CheckNoDeprecatedJS(input_api, output_api):
1395 """Make sure that we don't use deprecated JS in Chrome code."""
1396 results = []
1397 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1398 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1399 input_api.DEFAULT_BLACK_LIST)
1400 file_filter = lambda f: input_api.FilterSourceFile(
1401 f, white_list=file_inclusion_pattern, black_list=black_list)
1402 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1403 for lnum, line in fpath.ChangedContents():
1404 for (deprecated, replacement) in _DEPRECATED_JS:
1405 if deprecated in line:
1406 results.append(output_api.PresubmitError(
1407 "%s:%d: Use of deprecated JS %s, use %s instead" %
1408 (fpath.LocalPath(), lnum, deprecated, replacement)))
1409 return results
1410
1411
[email protected]22c9bd72011-03-27 16:47:391412def _CommonChecks(input_api, output_api):
1413 """Checks common to both upload and commit."""
1414 results = []
1415 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381416 input_api, output_api,
1417 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461418 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191419 results.extend(
[email protected]760deea2013-12-10 19:33:491420 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541421 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181422 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221423 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441424 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591425 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061426 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121427 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181428 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221429 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491430 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271431 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031432 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491433 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441434 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271435 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541436 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441437 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461438 # TODO(danakj): Remove this when base/move.h is removed.
1439 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551440 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041441 results.extend(
1442 input_api.canned_checks.CheckChangeHasNoTabs(
1443 input_api,
1444 output_api,
1445 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401446 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161447 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591448 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081449 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531450 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021451 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471452 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041453 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361454 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231455 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431456 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241457
1458 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1459 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1460 input_api, output_api,
1461 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381462 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391463 return results
[email protected]1f7b4172010-01-28 01:17:341464
[email protected]b337cb5b2011-01-23 21:24:051465
[email protected]66daa702011-05-28 14:41:461466def _CheckAuthorizedAuthor(input_api, output_api):
1467 """For non-googler/chromites committers, verify the author's email address is
1468 in AUTHORS.
1469 """
[email protected]9bb9cb82011-06-13 20:43:011470 # TODO(maruel): Add it to input_api?
1471 import fnmatch
1472
[email protected]66daa702011-05-28 14:41:461473 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011474 if not author:
1475 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461476 return []
[email protected]c99663292011-05-31 19:46:081477 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461478 input_api.PresubmitLocalPath(), 'AUTHORS')
1479 valid_authors = (
1480 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1481 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181482 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441483 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231484 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461485 return [output_api.PresubmitPromptWarning(
1486 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1487 '\n'
1488 'http://www.chromium.org/developers/contributing-code and read the '
1489 '"Legal" section\n'
1490 'If you are a chromite, verify the contributor signed the CLA.') %
1491 author)]
1492 return []
1493
1494
[email protected]b8079ae4a2012-12-05 19:56:491495def _CheckPatchFiles(input_api, output_api):
1496 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1497 if f.LocalPath().endswith(('.orig', '.rej'))]
1498 if problems:
1499 return [output_api.PresubmitError(
1500 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031501 else:
1502 return []
[email protected]b8079ae4a2012-12-05 19:56:491503
1504
[email protected]b00342e7f2013-03-26 16:21:541505def _DidYouMeanOSMacro(bad_macro):
1506 try:
1507 return {'A': 'OS_ANDROID',
1508 'B': 'OS_BSD',
1509 'C': 'OS_CHROMEOS',
1510 'F': 'OS_FREEBSD',
1511 'L': 'OS_LINUX',
1512 'M': 'OS_MACOSX',
1513 'N': 'OS_NACL',
1514 'O': 'OS_OPENBSD',
1515 'P': 'OS_POSIX',
1516 'S': 'OS_SOLARIS',
1517 'W': 'OS_WIN'}[bad_macro[3].upper()]
1518 except KeyError:
1519 return ''
1520
1521
1522def _CheckForInvalidOSMacrosInFile(input_api, f):
1523 """Check for sensible looking, totally invalid OS macros."""
1524 preprocessor_statement = input_api.re.compile(r'^\s*#')
1525 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1526 results = []
1527 for lnum, line in f.ChangedContents():
1528 if preprocessor_statement.search(line):
1529 for match in os_macro.finditer(line):
1530 if not match.group(1) in _VALID_OS_MACROS:
1531 good = _DidYouMeanOSMacro(match.group(1))
1532 did_you_mean = ' (did you mean %s?)' % good if good else ''
1533 results.append(' %s:%d %s%s' % (f.LocalPath(),
1534 lnum,
1535 match.group(1),
1536 did_you_mean))
1537 return results
1538
1539
1540def _CheckForInvalidOSMacros(input_api, output_api):
1541 """Check all affected files for invalid OS macros."""
1542 bad_macros = []
1543 for f in input_api.AffectedFiles():
1544 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1545 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1546
1547 if not bad_macros:
1548 return []
1549
1550 return [output_api.PresubmitError(
1551 'Possibly invalid OS macro[s] found. Please fix your code\n'
1552 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1553
lliabraa35bab3932014-10-01 12:16:441554
1555def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1556 """Check all affected files for invalid "if defined" macros."""
1557 ALWAYS_DEFINED_MACROS = (
1558 "TARGET_CPU_PPC",
1559 "TARGET_CPU_PPC64",
1560 "TARGET_CPU_68K",
1561 "TARGET_CPU_X86",
1562 "TARGET_CPU_ARM",
1563 "TARGET_CPU_MIPS",
1564 "TARGET_CPU_SPARC",
1565 "TARGET_CPU_ALPHA",
1566 "TARGET_IPHONE_SIMULATOR",
1567 "TARGET_OS_EMBEDDED",
1568 "TARGET_OS_IPHONE",
1569 "TARGET_OS_MAC",
1570 "TARGET_OS_UNIX",
1571 "TARGET_OS_WIN32",
1572 )
1573 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1574 results = []
1575 for lnum, line in f.ChangedContents():
1576 for match in ifdef_macro.finditer(line):
1577 if match.group(1) in ALWAYS_DEFINED_MACROS:
1578 always_defined = ' %s is always defined. ' % match.group(1)
1579 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1580 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1581 lnum,
1582 always_defined,
1583 did_you_mean))
1584 return results
1585
1586
1587def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1588 """Check all affected files for invalid "if defined" macros."""
1589 bad_macros = []
1590 for f in input_api.AffectedFiles():
1591 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1592 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1593
1594 if not bad_macros:
1595 return []
1596
1597 return [output_api.PresubmitError(
1598 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1599 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1600 bad_macros)]
1601
1602
danakj3c84d0c2014-10-06 15:35:461603def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1604 """Check all affected files for using side effects of Pass."""
1605 errors = []
1606 for f in input_api.AffectedFiles():
1607 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1608 for lnum, line in f.ChangedContents():
1609 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471610 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461611 errors.append(output_api.PresubmitError(
1612 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1613 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1614 return errors
1615
1616
mlamouria82272622014-09-16 18:45:041617def _CheckForIPCRules(input_api, output_api):
1618 """Check for same IPC rules described in
1619 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1620 """
1621 base_pattern = r'IPC_ENUM_TRAITS\('
1622 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1623 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1624
1625 problems = []
1626 for f in input_api.AffectedSourceFiles(None):
1627 local_path = f.LocalPath()
1628 if not local_path.endswith('.h'):
1629 continue
1630 for line_number, line in f.ChangedContents():
1631 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1632 problems.append(
1633 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1634
1635 if problems:
1636 return [output_api.PresubmitPromptWarning(
1637 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1638 else:
1639 return []
1640
[email protected]b00342e7f2013-03-26 16:21:541641
mostynbb639aca52015-01-07 20:31:231642def _CheckForWindowsLineEndings(input_api, output_api):
1643 """Check source code and known ascii text files for Windows style line
1644 endings.
1645 """
1646 known_text_files = r'.*\.(txt|html|htm|mhtml|py)$'
1647
1648 file_inclusion_pattern = (
1649 known_text_files,
1650 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1651 )
1652
1653 filter = lambda f: input_api.FilterSourceFile(
1654 f, white_list=file_inclusion_pattern, black_list=None)
1655 files = [f.LocalPath() for f in
1656 input_api.AffectedSourceFiles(filter)]
1657
1658 problems = []
1659
1660 for file in files:
1661 fp = open(file, 'r')
1662 for line in fp:
1663 if line.endswith('\r\n'):
1664 problems.append(file)
1665 break
1666 fp.close()
1667
1668 if problems:
1669 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1670 'these files to contain Windows style line endings?\n' +
1671 '\n'.join(problems))]
1672
1673 return []
1674
1675
[email protected]1f7b4172010-01-28 01:17:341676def CheckChangeOnUpload(input_api, output_api):
1677 results = []
1678 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471679 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171680 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281681 results.extend(
1682 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191683 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541684 return results
[email protected]ca8d19842009-02-19 16:33:121685
1686
[email protected]1bfb8322014-04-23 01:02:411687def GetTryServerMasterForBot(bot):
1688 """Returns the Try Server master for the given bot.
1689
[email protected]0bb112362014-07-26 04:38:321690 It tries to guess the master from the bot name, but may still fail
1691 and return None. There is no longer a default master.
1692 """
1693 # Potentially ambiguous bot names are listed explicitly.
1694 master_map = {
[email protected]0bb112362014-07-26 04:38:321695 'chromium_presubmit': 'tryserver.chromium.linux',
1696 'blink_presubmit': 'tryserver.chromium.linux',
1697 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411698 }
[email protected]0bb112362014-07-26 04:38:321699 master = master_map.get(bot)
1700 if not master:
1701 if 'gpu' in bot:
1702 master = 'tryserver.chromium.gpu'
1703 elif 'linux' in bot or 'android' in bot or 'presubmit' in bot:
1704 master = 'tryserver.chromium.linux'
1705 elif 'win' in bot:
1706 master = 'tryserver.chromium.win'
1707 elif 'mac' in bot or 'ios' in bot:
1708 master = 'tryserver.chromium.mac'
1709 return master
[email protected]1bfb8322014-04-23 01:02:411710
1711
Paweł Hajdan, Jr55083782014-12-19 20:32:561712def GetDefaultTryConfigs(bots):
1713 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011714 """
1715
Paweł Hajdan, Jr55083782014-12-19 20:32:561716 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411717
1718 # Build up the mapping from tryserver master to bot/test.
1719 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561720 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411721 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1722 return out
[email protected]38c6a512013-12-18 23:48:011723
1724
[email protected]ca8d19842009-02-19 16:33:121725def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541726 results = []
[email protected]1f7b4172010-01-28 01:17:341727 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511728 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1729 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1730 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541731 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271732 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341733 input_api,
1734 output_api,
[email protected]2fdd1f362013-01-16 03:56:031735 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271736
[email protected]3e4eb112011-01-18 03:29:541737 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1738 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411739 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1740 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541741 return results
[email protected]ca8d19842009-02-19 16:33:121742
1743
[email protected]7468ac522014-03-12 23:35:571744def GetPreferredTryMasters(project, change):
mohan.reddyf21db962014-10-16 12:26:471745 import re
[email protected]4ce995ea2012-06-27 02:13:101746 files = change.LocalPaths()
1747
Paweł Hajdan, Jref2afd42015-01-07 15:59:521748 import os
1749 import json
1750 with open(os.path.join(
1751 change.RepositoryRoot(), 'testing', 'commit_queue', 'config.json')) as f:
1752 cq_config = json.load(f)
1753 cq_trybots = cq_config.get('trybots', {})
1754 builders = cq_trybots.get('launched', {})
1755 for master, master_config in cq_trybots.get('triggered', {}).iteritems():
1756 for triggered_bot in master_config:
1757 builders.get(master, {}).pop(triggered_bot, None)
[email protected]911753b2012-08-02 12:11:541758
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321759 # Explicitly iterate over copies of dicts since we mutate them.
1760 for master in builders.keys():
1761 for builder in builders[master].keys():
1762 # Do not trigger presubmit builders, since they're likely to fail
1763 # (e.g. OWNERS checks before finished code review), and we're
1764 # running local presubmit anyway.
1765 if 'presubmit' in builder:
1766 builders[master].pop(builder)
1767
Paweł Hajdan, Jref2afd42015-01-07 15:59:521768 return builders