blob: 99c02609141f314e3bafe0d40bb9049826bf28db [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
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]ca8d1982009-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]ca8d1982009-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 = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
66 'collation (LC_COLLATE=C) and check https://google-styleguide.googlecode'
67 '.com/svn/trunk/cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
[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$",
dnicoara171d8c82015-03-05 20:46:18177 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
178 "drm_native_display_delegate\.cc$",
[email protected]7345da02012-11-27 14:31:49179 ),
[email protected]23e6cbc2012-06-16 18:51:20180 ),
[email protected]52657f62013-05-20 05:30:31181 (
182 'SkRefPtr',
183 (
184 'The use of SkRefPtr is prohibited. ',
185 'Please use skia::RefPtr instead.'
186 ),
187 True,
188 (),
189 ),
190 (
191 'SkAutoRef',
192 (
193 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
194 'Please use skia::RefPtr instead.'
195 ),
196 True,
197 (),
198 ),
199 (
200 'SkAutoTUnref',
201 (
202 'The use of SkAutoTUnref is dangerous because it implicitly ',
203 'converts to a raw pointer. Please use skia::RefPtr instead.'
204 ),
205 True,
206 (),
207 ),
208 (
209 'SkAutoUnref',
210 (
211 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
212 'because it implicitly converts to a raw pointer. ',
213 'Please use skia::RefPtr instead.'
214 ),
215 True,
216 (),
217 ),
[email protected]d89eec82013-12-03 14:10:59218 (
219 r'/HANDLE_EINTR\(.*close',
220 (
221 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
222 'descriptor will be closed, and it is incorrect to retry the close.',
223 'Either call close directly and ignore its return value, or wrap close',
224 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
225 ),
226 True,
227 (),
228 ),
229 (
230 r'/IGNORE_EINTR\((?!.*close)',
231 (
232 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
233 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
234 ),
235 True,
236 (
237 # Files that #define IGNORE_EINTR.
238 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
239 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
240 ),
241 ),
[email protected]ec5b3f02014-04-04 18:43:43242 (
243 r'/v8::Extension\(',
244 (
245 'Do not introduce new v8::Extensions into the code base, use',
246 'gin::Wrappable instead. See http://crbug.com/334679',
247 ),
248 True,
[email protected]f55c90ee62014-04-12 00:50:03249 (
joaodasilva718f87672014-08-30 09:25:49250 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03251 ),
[email protected]ec5b3f02014-04-04 18:43:43252 ),
skyostilf9469f72015-04-20 10:38:52253 (
254 'MessageLoopProxy',
255 (
256 'MessageLoopProxy is deprecated. ',
257 'Please use SingleThreadTaskRunner or ThreadTaskRunnerHandle instead.'
258 ),
259 True,
260 (),
261 ),
[email protected]127f18ec2012-06-16 05:05:59262)
263
mlamouria82272622014-09-16 18:45:04264_IPC_ENUM_TRAITS_DEPRECATED = (
265 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
266 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
267
[email protected]127f18ec2012-06-16 05:05:59268
[email protected]b00342e7f2013-03-26 16:21:54269_VALID_OS_MACROS = (
270 # Please keep sorted.
271 'OS_ANDROID',
[email protected]f4440b42014-03-19 05:47:01272 'OS_ANDROID_HOST',
[email protected]b00342e7f2013-03-26 16:21:54273 'OS_BSD',
274 'OS_CAT', # For testing.
275 'OS_CHROMEOS',
276 'OS_FREEBSD',
277 'OS_IOS',
278 'OS_LINUX',
279 'OS_MACOSX',
280 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21281 'OS_NACL_NONSFI',
282 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54283 'OS_OPENBSD',
284 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37285 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54286 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54287 'OS_WIN',
288)
289
290
[email protected]55459852011-08-10 15:17:19291def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
292 """Attempts to prevent use of functions intended only for testing in
293 non-testing code. For now this is just a best-effort implementation
294 that ignores header files and may have some false positives. A
295 better implementation would probably need a proper C++ parser.
296 """
297 # We only scan .cc files and the like, as the declaration of
298 # for-testing functions in header files are hard to distinguish from
299 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44300 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19301
[email protected]23501822014-05-14 02:06:09302 base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?'
[email protected]55459852011-08-10 15:17:19303 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09304 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19305 exclusion_pattern = input_api.re.compile(
306 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
307 base_function_pattern, base_function_pattern))
308
309 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44310 black_list = (_EXCLUDED_PATHS +
311 _TEST_CODE_EXCLUDED_PATHS +
312 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19313 return input_api.FilterSourceFile(
314 affected_file,
315 white_list=(file_inclusion_pattern, ),
316 black_list=black_list)
317
318 problems = []
319 for f in input_api.AffectedSourceFiles(FilterFile):
320 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24321 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03322 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46323 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03324 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19325 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03326 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19327
328 if problems:
[email protected]f7051d52013-04-02 18:31:42329 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03330 else:
331 return []
[email protected]55459852011-08-10 15:17:19332
333
[email protected]10689ca2011-09-02 02:31:54334def _CheckNoIOStreamInHeaders(input_api, output_api):
335 """Checks to make sure no .h files include <iostream>."""
336 files = []
337 pattern = input_api.re.compile(r'^#include\s*<iostream>',
338 input_api.re.MULTILINE)
339 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
340 if not f.LocalPath().endswith('.h'):
341 continue
342 contents = input_api.ReadFile(f)
343 if pattern.search(contents):
344 files.append(f)
345
346 if len(files):
347 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06348 'Do not #include <iostream> in header files, since it inserts static '
349 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54350 '#include <ostream>. See http://crbug.com/94794',
351 files) ]
352 return []
353
354
[email protected]72df4e782012-06-21 16:28:18355def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
356 """Checks to make sure no source files use UNIT_TEST"""
357 problems = []
358 for f in input_api.AffectedFiles():
359 if (not f.LocalPath().endswith(('.cc', '.mm'))):
360 continue
361
362 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04363 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18364 problems.append(' %s:%d' % (f.LocalPath(), line_num))
365
366 if not problems:
367 return []
368 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
369 '\n'.join(problems))]
370
371
mcasasb7440c282015-02-04 14:52:19372def _FindHistogramNameInLine(histogram_name, line):
373 """Tries to find a histogram name or prefix in a line."""
374 if not "affected-histogram" in line:
375 return histogram_name in line
376 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
377 # the histogram_name.
378 if not '"' in line:
379 return False
380 histogram_prefix = line.split('\"')[1]
381 return histogram_prefix in histogram_name
382
383
384def _CheckUmaHistogramChanges(input_api, output_api):
385 """Check that UMA histogram names in touched lines can still be found in other
386 lines of the patch or in histograms.xml. Note that this check would not catch
387 the reverse: changes in histograms.xml not matched in the code itself."""
388 touched_histograms = []
389 histograms_xml_modifications = []
390 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
391 for f in input_api.AffectedFiles():
392 # If histograms.xml itself is modified, keep the modified lines for later.
393 if f.LocalPath().endswith(('histograms.xml')):
394 histograms_xml_modifications = f.ChangedContents()
395 continue
396 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
397 continue
398 for line_num, line in f.ChangedContents():
399 found = pattern.search(line)
400 if found:
401 touched_histograms.append([found.group(1), f, line_num])
402
403 # Search for the touched histogram names in the local modifications to
404 # histograms.xml, and, if not found, on the base histograms.xml file.
405 unmatched_histograms = []
406 for histogram_info in touched_histograms:
407 histogram_name_found = False
408 for line_num, line in histograms_xml_modifications:
409 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
410 if histogram_name_found:
411 break
412 if not histogram_name_found:
413 unmatched_histograms.append(histogram_info)
414
eromanb90c82e7e32015-04-01 15:13:49415 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19416 problems = []
417 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49418 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19419 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45420 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19421 histogram_name_found = False
422 for line in histograms_xml:
423 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
424 if histogram_name_found:
425 break
426 if not histogram_name_found:
427 problems.append(' [%s:%d] %s' %
428 (f.LocalPath(), line_num, histogram_name))
429
430 if not problems:
431 return []
432 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
433 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49434 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19435
436
[email protected]8ea5d4b2011-09-13 21:49:22437def _CheckNoNewWStrings(input_api, output_api):
438 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27439 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22440 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20441 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57442 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
443 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20444 continue
[email protected]8ea5d4b2011-09-13 21:49:22445
[email protected]a11dbe9b2012-08-07 01:32:58446 allowWString = False
[email protected]b5c24292011-11-28 14:38:20447 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58448 if 'presubmit: allow wstring' in line:
449 allowWString = True
450 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27451 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58452 allowWString = False
453 else:
454 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22455
[email protected]55463aa62011-10-12 00:48:27456 if not problems:
457 return []
458 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58459 ' If you are calling a cross-platform API that accepts a wstring, '
460 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27461 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22462
463
[email protected]2a8ac9c2011-10-19 17:20:44464def _CheckNoDEPSGIT(input_api, output_api):
465 """Make sure .DEPS.git is never modified manually."""
466 if any(f.LocalPath().endswith('.DEPS.git') for f in
467 input_api.AffectedFiles()):
468 return [output_api.PresubmitError(
469 'Never commit changes to .DEPS.git. This file is maintained by an\n'
470 'automated system based on what\'s in DEPS and your changes will be\n'
471 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34472 '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:44473 'for more information')]
474 return []
475
476
tandriief664692014-09-23 14:51:47477def _CheckValidHostsInDEPS(input_api, output_api):
478 """Checks that DEPS file deps are from allowed_hosts."""
479 # Run only if DEPS file has been modified to annoy fewer bystanders.
480 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
481 return []
482 # Outsource work to gclient verify
483 try:
484 input_api.subprocess.check_output(['gclient', 'verify'])
485 return []
486 except input_api.subprocess.CalledProcessError, error:
487 return [output_api.PresubmitError(
488 'DEPS file must have only git dependencies.',
489 long_text=error.output)]
490
491
[email protected]127f18ec2012-06-16 05:05:59492def _CheckNoBannedFunctions(input_api, output_api):
493 """Make sure that banned functions are not used."""
494 warnings = []
495 errors = []
496
497 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
498 for f in input_api.AffectedFiles(file_filter=file_filter):
499 for line_num, line in f.ChangedContents():
500 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26501 matched = False
502 if func_name[0:1] == '/':
503 regex = func_name[1:]
504 if input_api.re.search(regex, line):
505 matched = True
506 elif func_name in line:
507 matched = True
508 if matched:
[email protected]127f18ec2012-06-16 05:05:59509 problems = warnings;
510 if error:
511 problems = errors;
512 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
513 for message_line in message:
514 problems.append(' %s' % message_line)
515
516 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
517 for f in input_api.AffectedFiles(file_filter=file_filter):
518 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49519 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
520 def IsBlacklisted(affected_file, blacklist):
521 local_path = affected_file.LocalPath()
522 for item in blacklist:
523 if input_api.re.match(item, local_path):
524 return True
525 return False
526 if IsBlacklisted(f, excluded_paths):
527 continue
[email protected]d89eec82013-12-03 14:10:59528 matched = False
529 if func_name[0:1] == '/':
530 regex = func_name[1:]
531 if input_api.re.search(regex, line):
532 matched = True
533 elif func_name in line:
534 matched = True
535 if matched:
[email protected]127f18ec2012-06-16 05:05:59536 problems = warnings;
537 if error:
538 problems = errors;
539 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
540 for message_line in message:
541 problems.append(' %s' % message_line)
542
543 result = []
544 if (warnings):
545 result.append(output_api.PresubmitPromptWarning(
546 'Banned functions were used.\n' + '\n'.join(warnings)))
547 if (errors):
548 result.append(output_api.PresubmitError(
549 'Banned functions were used.\n' + '\n'.join(errors)))
550 return result
551
552
[email protected]6c063c62012-07-11 19:11:06553def _CheckNoPragmaOnce(input_api, output_api):
554 """Make sure that banned functions are not used."""
555 files = []
556 pattern = input_api.re.compile(r'^#pragma\s+once',
557 input_api.re.MULTILINE)
558 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
559 if not f.LocalPath().endswith('.h'):
560 continue
561 contents = input_api.ReadFile(f)
562 if pattern.search(contents):
563 files.append(f)
564
565 if files:
566 return [output_api.PresubmitError(
567 'Do not use #pragma once in header files.\n'
568 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
569 files)]
570 return []
571
[email protected]127f18ec2012-06-16 05:05:59572
[email protected]e7479052012-09-19 00:26:12573def _CheckNoTrinaryTrueFalse(input_api, output_api):
574 """Checks to make sure we don't introduce use of foo ? true : false."""
575 problems = []
576 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
577 for f in input_api.AffectedFiles():
578 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
579 continue
580
581 for line_num, line in f.ChangedContents():
582 if pattern.match(line):
583 problems.append(' %s:%d' % (f.LocalPath(), line_num))
584
585 if not problems:
586 return []
587 return [output_api.PresubmitPromptWarning(
588 'Please consider avoiding the "? true : false" pattern if possible.\n' +
589 '\n'.join(problems))]
590
591
[email protected]55f9f382012-07-31 11:02:18592def _CheckUnwantedDependencies(input_api, output_api):
593 """Runs checkdeps on #include statements added in this
594 change. Breaking - rules is an error, breaking ! rules is a
595 warning.
596 """
mohan.reddyf21db962014-10-16 12:26:47597 import sys
[email protected]55f9f382012-07-31 11:02:18598 # We need to wait until we have an input_api object and use this
599 # roundabout construct to import checkdeps because this file is
600 # eval-ed and thus doesn't have __file__.
601 original_sys_path = sys.path
602 try:
603 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47604 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18605 import checkdeps
606 from cpp_checker import CppChecker
607 from rules import Rule
608 finally:
609 # Restore sys.path to what it was before.
610 sys.path = original_sys_path
611
612 added_includes = []
613 for f in input_api.AffectedFiles():
614 if not CppChecker.IsCppFile(f.LocalPath()):
615 continue
616
617 changed_lines = [line for line_num, line in f.ChangedContents()]
618 added_includes.append([f.LocalPath(), changed_lines])
619
[email protected]26385172013-05-09 23:11:35620 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18621
622 error_descriptions = []
623 warning_descriptions = []
624 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
625 added_includes):
626 description_with_path = '%s\n %s' % (path, rule_description)
627 if rule_type == Rule.DISALLOW:
628 error_descriptions.append(description_with_path)
629 else:
630 warning_descriptions.append(description_with_path)
631
632 results = []
633 if error_descriptions:
634 results.append(output_api.PresubmitError(
635 'You added one or more #includes that violate checkdeps rules.',
636 error_descriptions))
637 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42638 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18639 'You added one or more #includes of files that are temporarily\n'
640 'allowed but being removed. Can you avoid introducing the\n'
641 '#include? See relevant DEPS file(s) for details and contacts.',
642 warning_descriptions))
643 return results
644
645
[email protected]fbcafe5a2012-08-08 15:31:22646def _CheckFilePermissions(input_api, output_api):
647 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15648 if input_api.platform == 'win32':
649 return []
mohan.reddyf21db962014-10-16 12:26:47650 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
651 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22652 for f in input_api.AffectedFiles():
653 args += ['--file', f.LocalPath()]
[email protected]f0d330f2014-01-30 01:44:34654 checkperms = input_api.subprocess.Popen(args,
655 stdout=input_api.subprocess.PIPE)
656 errors = checkperms.communicate()[0].strip()
[email protected]fbcafe5a2012-08-08 15:31:22657 if errors:
[email protected]f0d330f2014-01-30 01:44:34658 return [output_api.PresubmitError('checkperms.py failed.',
659 errors.splitlines())]
660 return []
[email protected]fbcafe5a2012-08-08 15:31:22661
662
[email protected]c8278b32012-10-30 20:35:49663def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
664 """Makes sure we don't include ui/aura/window_property.h
665 in header files.
666 """
667 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
668 errors = []
669 for f in input_api.AffectedFiles():
670 if not f.LocalPath().endswith('.h'):
671 continue
672 for line_num, line in f.ChangedContents():
673 if pattern.match(line):
674 errors.append(' %s:%d' % (f.LocalPath(), line_num))
675
676 results = []
677 if errors:
678 results.append(output_api.PresubmitError(
679 'Header files should not include ui/aura/window_property.h', errors))
680 return results
681
682
[email protected]cf9b78f2012-11-14 11:40:28683def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
684 """Checks that the lines in scope occur in the right order.
685
686 1. C system files in alphabetical order
687 2. C++ system files in alphabetical order
688 3. Project's .h files
689 """
690
691 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
692 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
693 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
694
695 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
696
697 state = C_SYSTEM_INCLUDES
698
699 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57700 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28701 problem_linenums = []
702 for line_num, line in scope:
703 if c_system_include_pattern.match(line):
704 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57705 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28706 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57707 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28708 elif cpp_system_include_pattern.match(line):
709 if state == C_SYSTEM_INCLUDES:
710 state = CPP_SYSTEM_INCLUDES
711 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57712 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28713 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57714 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28715 elif custom_include_pattern.match(line):
716 if state != CUSTOM_INCLUDES:
717 state = CUSTOM_INCLUDES
718 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57719 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28720 else:
721 problem_linenums.append(line_num)
722 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57723 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28724
725 warnings = []
[email protected]728b9bb2012-11-14 20:38:57726 for (line_num, previous_line_num) in problem_linenums:
727 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28728 warnings.append(' %s:%d' % (file_path, line_num))
729 return warnings
730
731
[email protected]ac294a12012-12-06 16:38:43732def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28733 """Checks the #include order for the given file f."""
734
[email protected]2299dcf2012-11-15 19:56:24735 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30736 # Exclude the following includes from the check:
737 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
738 # specific order.
739 # 2) <atlbase.h>, "build/build_config.h"
740 excluded_include_pattern = input_api.re.compile(
741 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24742 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33743 # Match the final or penultimate token if it is xxxtest so we can ignore it
744 # when considering the special first include.
745 test_file_tag_pattern = input_api.re.compile(
746 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11747 if_pattern = input_api.re.compile(
748 r'\s*#\s*(if|elif|else|endif|define|undef).*')
749 # Some files need specialized order of includes; exclude such files from this
750 # check.
751 uncheckable_includes_pattern = input_api.re.compile(
752 r'\s*#include '
753 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28754
755 contents = f.NewContents()
756 warnings = []
757 line_num = 0
758
[email protected]ac294a12012-12-06 16:38:43759 # Handle the special first include. If the first include file is
760 # some/path/file.h, the corresponding including file can be some/path/file.cc,
761 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
762 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33763 # If the included file is some/path/file_platform.h the including file could
764 # also be some/path/file_xxxtest_platform.h.
765 including_file_base_name = test_file_tag_pattern.sub(
766 '', input_api.os_path.basename(f.LocalPath()))
767
[email protected]ac294a12012-12-06 16:38:43768 for line in contents:
769 line_num += 1
770 if system_include_pattern.match(line):
771 # No special first include -> process the line again along with normal
772 # includes.
773 line_num -= 1
774 break
775 match = custom_include_pattern.match(line)
776 if match:
777 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33778 header_basename = test_file_tag_pattern.sub(
779 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
780
781 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24782 # No special first include -> process the line again along with normal
783 # includes.
784 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43785 break
[email protected]cf9b78f2012-11-14 11:40:28786
787 # Split into scopes: Each region between #if and #endif is its own scope.
788 scopes = []
789 current_scope = []
790 for line in contents[line_num:]:
791 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11792 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54793 continue
[email protected]2309b0fa02012-11-16 12:18:27794 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28795 scopes.append(current_scope)
796 current_scope = []
[email protected]962f117e2012-11-22 18:11:56797 elif ((system_include_pattern.match(line) or
798 custom_include_pattern.match(line)) and
799 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28800 current_scope.append((line_num, line))
801 scopes.append(current_scope)
802
803 for scope in scopes:
804 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
805 changed_linenums))
806 return warnings
807
808
809def _CheckIncludeOrder(input_api, output_api):
810 """Checks that the #include order is correct.
811
812 1. The corresponding header for source files.
813 2. C system files in alphabetical order
814 3. C++ system files in alphabetical order
815 4. Project's .h files in alphabetical order
816
[email protected]ac294a12012-12-06 16:38:43817 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
818 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28819 """
[email protected]e120b012014-08-15 19:08:35820 def FileFilterIncludeOrder(affected_file):
821 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
822 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28823
824 warnings = []
[email protected]e120b012014-08-15 19:08:35825 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
[email protected]ac294a12012-12-06 16:38:43826 if f.LocalPath().endswith(('.cc', '.h')):
827 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
828 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28829
830 results = []
831 if warnings:
[email protected]f7051d52013-04-02 18:31:42832 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53833 warnings))
[email protected]cf9b78f2012-11-14 11:40:28834 return results
835
836
[email protected]70ca77752012-11-20 03:45:03837def _CheckForVersionControlConflictsInFile(input_api, f):
838 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
839 errors = []
840 for line_num, line in f.ChangedContents():
841 if pattern.match(line):
842 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
843 return errors
844
845
846def _CheckForVersionControlConflicts(input_api, output_api):
847 """Usually this is not intentional and will cause a compile failure."""
848 errors = []
849 for f in input_api.AffectedFiles():
850 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
851
852 results = []
853 if errors:
854 results.append(output_api.PresubmitError(
855 'Version control conflict markers found, please resolve.', errors))
856 return results
857
858
[email protected]06e6d0ff2012-12-11 01:36:44859def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
860 def FilterFile(affected_file):
861 """Filter function for use with input_api.AffectedSourceFiles,
862 below. This filters out everything except non-test files from
863 top-level directories that generally speaking should not hard-code
864 service URLs (e.g. src/android_webview/, src/content/ and others).
865 """
866 return input_api.FilterSourceFile(
867 affected_file,
[email protected]78bb39d62012-12-11 15:11:56868 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44869 black_list=(_EXCLUDED_PATHS +
870 _TEST_CODE_EXCLUDED_PATHS +
871 input_api.DEFAULT_BLACK_LIST))
872
[email protected]de4f7d22013-05-23 14:27:46873 base_pattern = '"[^"]*google\.com[^"]*"'
874 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
875 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44876 problems = [] # items are (filename, line_number, line)
877 for f in input_api.AffectedSourceFiles(FilterFile):
878 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46879 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44880 problems.append((f.LocalPath(), line_num, line))
881
882 if problems:
[email protected]f7051d52013-04-02 18:31:42883 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44884 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58885 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44886 [' %s:%d: %s' % (
887 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03888 else:
889 return []
[email protected]06e6d0ff2012-12-11 01:36:44890
891
[email protected]d2530012013-01-25 16:39:27892def _CheckNoAbbreviationInPngFileName(input_api, output_api):
893 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31894 The native_client_sdk directory is excluded because it has auto-generated PNG
895 files for documentation.
[email protected]d2530012013-01-25 16:39:27896 """
[email protected]d2530012013-01-25 16:39:27897 errors = []
binji0dcdf342014-12-12 18:32:31898 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
899 black_list = (r'^native_client_sdk[\\\/]',)
900 file_filter = lambda f: input_api.FilterSourceFile(
901 f, white_list=white_list, black_list=black_list)
902 for f in input_api.AffectedFiles(include_deletes=False,
903 file_filter=file_filter):
904 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27905
906 results = []
907 if errors:
908 results.append(output_api.PresubmitError(
909 'The name of PNG files should not have abbreviations. \n'
910 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
911 'Contact [email protected] if you have questions.', errors))
912 return results
913
914
[email protected]14a6131c2014-01-08 01:15:41915def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08916 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41917 a set of DEPS entries that we should look up.
918
919 For a directory (rather than a specific filename) we fake a path to
920 a specific filename by adding /DEPS. This is chosen as a file that
921 will seldom or never be subject to per-file include_rules.
922 """
[email protected]2b438d62013-11-14 17:54:14923 # We ignore deps entries on auto-generated directories.
924 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08925
926 # This pattern grabs the path without basename in the first
927 # parentheses, and the basename (if present) in the second. It
928 # relies on the simple heuristic that if there is a basename it will
929 # be a header file ending in ".h".
930 pattern = re.compile(
931 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14932 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08933 for changed_line in changed_lines:
934 m = pattern.match(changed_line)
935 if m:
936 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14937 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41938 if m.group(2):
939 results.add('%s%s' % (path, m.group(2)))
940 else:
941 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08942 return results
943
944
[email protected]e871964c2013-05-13 14:14:55945def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
946 """When a dependency prefixed with + is added to a DEPS file, we
947 want to make sure that the change is reviewed by an OWNER of the
948 target file or directory, to avoid layering violations from being
949 introduced. This check verifies that this happens.
950 """
951 changed_lines = set()
952 for f in input_api.AffectedFiles():
953 filename = input_api.os_path.basename(f.LocalPath())
954 if filename == 'DEPS':
955 changed_lines |= set(line.strip()
956 for line_num, line
957 in f.ChangedContents())
958 if not changed_lines:
959 return []
960
[email protected]14a6131c2014-01-08 01:15:41961 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
962 changed_lines)
[email protected]e871964c2013-05-13 14:14:55963 if not virtual_depended_on_files:
964 return []
965
966 if input_api.is_committing:
967 if input_api.tbr:
968 return [output_api.PresubmitNotifyResult(
969 '--tbr was specified, skipping OWNERS check for DEPS additions')]
970 if not input_api.change.issue:
971 return [output_api.PresubmitError(
972 "DEPS approval by OWNERS check failed: this change has "
973 "no Rietveld issue number, so we can't check it for approvals.")]
974 output = output_api.PresubmitError
975 else:
976 output = output_api.PresubmitNotifyResult
977
978 owners_db = input_api.owners_db
979 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
980 input_api,
981 owners_db.email_regexp,
982 approval_needed=input_api.is_committing)
983
984 owner_email = owner_email or input_api.change.author_email
985
[email protected]de4f7d22013-05-23 14:27:46986 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:51987 if owner_email:
[email protected]de4f7d22013-05-23 14:27:46988 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:55989 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
990 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:41991
992 # We strip the /DEPS part that was added by
993 # _FilesToCheckForIncomingDeps to fake a path to a file in a
994 # directory.
995 def StripDeps(path):
996 start_deps = path.rfind('/DEPS')
997 if start_deps != -1:
998 return path[:start_deps]
999 else:
1000 return path
1001 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551002 for path in missing_files]
1003
1004 if unapproved_dependencies:
1005 output_list = [
[email protected]14a6131c2014-01-08 01:15:411006 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:551007 '\n '.join(sorted(unapproved_dependencies)))]
1008 if not input_api.is_committing:
1009 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1010 output_list.append(output(
1011 'Suggested missing target path OWNERS:\n %s' %
1012 '\n '.join(suggested_owners or [])))
1013 return output_list
1014
1015 return []
1016
1017
[email protected]85218562013-11-22 07:41:401018def _CheckSpamLogging(input_api, output_api):
1019 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1020 black_list = (_EXCLUDED_PATHS +
1021 _TEST_CODE_EXCLUDED_PATHS +
1022 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501023 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191024 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481025 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461026 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121027 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1028 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581029 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161030 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031031 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151032 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1033 r"^chromecast[\\\/]",
1034 r"^cloud_print[\\\/]",
[email protected]9056e732014-01-08 06:25:251035 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1036 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111037 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151038 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111039 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521040 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501041 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361042 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311043 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131044 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441045 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021046 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441047 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401048 source_file_filter = lambda x: input_api.FilterSourceFile(
1049 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1050
1051 log_info = []
1052 printf = []
1053
1054 for f in input_api.AffectedSourceFiles(source_file_filter):
1055 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471056 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401057 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471058 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131059 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371060
mohan.reddyf21db962014-10-16 12:26:471061 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371062 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471063 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401064 printf.append(f.LocalPath())
1065
1066 if log_info:
1067 return [output_api.PresubmitError(
1068 'These files spam the console log with LOG(INFO):',
1069 items=log_info)]
1070 if printf:
1071 return [output_api.PresubmitError(
1072 'These files spam the console log with printf/fprintf:',
1073 items=printf)]
1074 return []
1075
1076
[email protected]49aa76a2013-12-04 06:59:161077def _CheckForAnonymousVariables(input_api, output_api):
1078 """These types are all expected to hold locks while in scope and
1079 so should never be anonymous (which causes them to be immediately
1080 destroyed)."""
1081 they_who_must_be_named = [
1082 'base::AutoLock',
1083 'base::AutoReset',
1084 'base::AutoUnlock',
1085 'SkAutoAlphaRestore',
1086 'SkAutoBitmapShaderInstall',
1087 'SkAutoBlitterChoose',
1088 'SkAutoBounderCommit',
1089 'SkAutoCallProc',
1090 'SkAutoCanvasRestore',
1091 'SkAutoCommentBlock',
1092 'SkAutoDescriptor',
1093 'SkAutoDisableDirectionCheck',
1094 'SkAutoDisableOvalCheck',
1095 'SkAutoFree',
1096 'SkAutoGlyphCache',
1097 'SkAutoHDC',
1098 'SkAutoLockColors',
1099 'SkAutoLockPixels',
1100 'SkAutoMalloc',
1101 'SkAutoMaskFreeImage',
1102 'SkAutoMutexAcquire',
1103 'SkAutoPathBoundsUpdate',
1104 'SkAutoPDFRelease',
1105 'SkAutoRasterClipValidate',
1106 'SkAutoRef',
1107 'SkAutoTime',
1108 'SkAutoTrace',
1109 'SkAutoUnref',
1110 ]
1111 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1112 # bad: base::AutoLock(lock.get());
1113 # not bad: base::AutoLock lock(lock.get());
1114 bad_pattern = input_api.re.compile(anonymous)
1115 # good: new base::AutoLock(lock.get())
1116 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1117 errors = []
1118
1119 for f in input_api.AffectedFiles():
1120 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1121 continue
1122 for linenum, line in f.ChangedContents():
1123 if bad_pattern.search(line) and not good_pattern.search(line):
1124 errors.append('%s:%d' % (f.LocalPath(), linenum))
1125
1126 if errors:
1127 return [output_api.PresubmitError(
1128 'These lines create anonymous variables that need to be named:',
1129 items=errors)]
1130 return []
1131
1132
[email protected]5fe0f8742013-11-29 01:04:591133def _CheckCygwinShell(input_api, output_api):
1134 source_file_filter = lambda x: input_api.FilterSourceFile(
1135 x, white_list=(r'.+\.(gyp|gypi)$',))
1136 cygwin_shell = []
1137
1138 for f in input_api.AffectedSourceFiles(source_file_filter):
1139 for linenum, line in f.ChangedContents():
1140 if 'msvs_cygwin_shell' in line:
1141 cygwin_shell.append(f.LocalPath())
1142 break
1143
1144 if cygwin_shell:
1145 return [output_api.PresubmitError(
1146 'These files should not use msvs_cygwin_shell (the default is 0):',
1147 items=cygwin_shell)]
1148 return []
1149
[email protected]85218562013-11-22 07:41:401150
[email protected]999261d2014-03-03 20:08:081151def _CheckUserActionUpdate(input_api, output_api):
1152 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521153 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081154 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521155 # If actions.xml is already included in the changelist, the PRESUBMIT
1156 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081157 return []
1158
[email protected]999261d2014-03-03 20:08:081159 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1160 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521161 current_actions = None
[email protected]999261d2014-03-03 20:08:081162 for f in input_api.AffectedFiles(file_filter=file_filter):
1163 for line_num, line in f.ChangedContents():
1164 match = input_api.re.search(action_re, line)
1165 if match:
[email protected]2f92dec2014-03-07 19:21:521166 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1167 # loaded only once.
1168 if not current_actions:
1169 with open('tools/metrics/actions/actions.xml') as actions_f:
1170 current_actions = actions_f.read()
1171 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081172 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521173 action = 'name="{0}"'.format(action_name)
1174 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081175 return [output_api.PresubmitPromptWarning(
1176 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521177 'tools/metrics/actions/actions.xml. Please run '
1178 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081179 % (f.LocalPath(), line_num, action_name))]
1180 return []
1181
1182
[email protected]99171a92014-06-03 08:44:471183def _GetJSONParseError(input_api, filename, eat_comments=True):
1184 try:
1185 contents = input_api.ReadFile(filename)
1186 if eat_comments:
1187 json_comment_eater = input_api.os_path.join(
1188 input_api.PresubmitLocalPath(),
1189 'tools', 'json_comment_eater', 'json_comment_eater.py')
1190 process = input_api.subprocess.Popen(
1191 [input_api.python_executable, json_comment_eater],
1192 stdin=input_api.subprocess.PIPE,
1193 stdout=input_api.subprocess.PIPE,
1194 universal_newlines=True)
1195 (contents, _) = process.communicate(input=contents)
1196
1197 input_api.json.loads(contents)
1198 except ValueError as e:
1199 return e
1200 return None
1201
1202
1203def _GetIDLParseError(input_api, filename):
1204 try:
1205 contents = input_api.ReadFile(filename)
1206 idl_schema = input_api.os_path.join(
1207 input_api.PresubmitLocalPath(),
1208 'tools', 'json_schema_compiler', 'idl_schema.py')
1209 process = input_api.subprocess.Popen(
1210 [input_api.python_executable, idl_schema],
1211 stdin=input_api.subprocess.PIPE,
1212 stdout=input_api.subprocess.PIPE,
1213 stderr=input_api.subprocess.PIPE,
1214 universal_newlines=True)
1215 (_, error) = process.communicate(input=contents)
1216 return error or None
1217 except ValueError as e:
1218 return e
1219
1220
1221def _CheckParseErrors(input_api, output_api):
1222 """Check that IDL and JSON files do not contain syntax errors."""
1223 actions = {
1224 '.idl': _GetIDLParseError,
1225 '.json': _GetJSONParseError,
1226 }
1227 # These paths contain test data and other known invalid JSON files.
1228 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491229 r'test[\\\/]data[\\\/]',
1230 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471231 ]
1232 # Most JSON files are preprocessed and support comments, but these do not.
1233 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491234 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471235 ]
1236 # Only run IDL checker on files in these directories.
1237 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491238 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1239 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471240 ]
1241
1242 def get_action(affected_file):
1243 filename = affected_file.LocalPath()
1244 return actions.get(input_api.os_path.splitext(filename)[1])
1245
1246 def MatchesFile(patterns, path):
1247 for pattern in patterns:
1248 if input_api.re.search(pattern, path):
1249 return True
1250 return False
1251
1252 def FilterFile(affected_file):
1253 action = get_action(affected_file)
1254 if not action:
1255 return False
1256 path = affected_file.LocalPath()
1257
1258 if MatchesFile(excluded_patterns, path):
1259 return False
1260
1261 if (action == _GetIDLParseError and
1262 not MatchesFile(idl_included_patterns, path)):
1263 return False
1264 return True
1265
1266 results = []
1267 for affected_file in input_api.AffectedFiles(
1268 file_filter=FilterFile, include_deletes=False):
1269 action = get_action(affected_file)
1270 kwargs = {}
1271 if (action == _GetJSONParseError and
1272 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1273 kwargs['eat_comments'] = False
1274 parse_error = action(input_api,
1275 affected_file.AbsoluteLocalPath(),
1276 **kwargs)
1277 if parse_error:
1278 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1279 (affected_file.LocalPath(), parse_error)))
1280 return results
1281
1282
[email protected]760deea2013-12-10 19:33:491283def _CheckJavaStyle(input_api, output_api):
1284 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471285 import sys
[email protected]760deea2013-12-10 19:33:491286 original_sys_path = sys.path
1287 try:
1288 sys.path = sys.path + [input_api.os_path.join(
1289 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1290 import checkstyle
1291 finally:
1292 # Restore sys.path to what it was before.
1293 sys.path = original_sys_path
1294
1295 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091296 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511297 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491298
1299
mnaganov9b9b1fe82014-12-11 16:30:361300def _CheckForCopyrightedCode(input_api, output_api):
1301 """Verifies that newly added code doesn't contain copyrighted material
1302 and is properly licensed under the standard Chromium license.
1303
1304 As there can be false positives, we maintain a whitelist file. This check
1305 also verifies that the whitelist file is up to date.
1306 """
1307 import sys
1308 original_sys_path = sys.path
1309 try:
1310 sys.path = sys.path + [input_api.os_path.join(
1311 input_api.PresubmitLocalPath(), 'android_webview', 'tools')]
1312 import copyright_scanner
1313 finally:
1314 # Restore sys.path to what it was before.
1315 sys.path = original_sys_path
1316
1317 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1318
1319
glidere61efad2015-02-18 17:39:431320def _CheckSingletonInHeaders(input_api, output_api):
1321 """Checks to make sure no header files have |Singleton<|."""
1322 def FileFilter(affected_file):
1323 # It's ok for base/memory/singleton.h to have |Singleton<|.
1324 black_list = (_EXCLUDED_PATHS +
1325 input_api.DEFAULT_BLACK_LIST +
1326 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1327 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1328
1329 pattern = input_api.re.compile(r'(?<!class\s)Singleton\s*<')
1330 files = []
1331 for f in input_api.AffectedSourceFiles(FileFilter):
1332 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1333 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1334 contents = input_api.ReadFile(f)
1335 for line in contents.splitlines(False):
1336 if (not input_api.re.match(r'//', line) and # Strip C++ comment.
1337 pattern.search(line)):
1338 files.append(f)
1339 break
1340
1341 if files:
1342 return [ output_api.PresubmitError(
1343 'Found Singleton<T> in the following header files.\n' +
1344 'Please move them to an appropriate source file so that the ' +
1345 'template gets instantiated in a single compilation unit.',
1346 files) ]
1347 return []
1348
1349
[email protected]fd20b902014-05-09 02:14:531350_DEPRECATED_CSS = [
1351 # Values
1352 ( "-webkit-box", "flex" ),
1353 ( "-webkit-inline-box", "inline-flex" ),
1354 ( "-webkit-flex", "flex" ),
1355 ( "-webkit-inline-flex", "inline-flex" ),
1356 ( "-webkit-min-content", "min-content" ),
1357 ( "-webkit-max-content", "max-content" ),
1358
1359 # Properties
1360 ( "-webkit-background-clip", "background-clip" ),
1361 ( "-webkit-background-origin", "background-origin" ),
1362 ( "-webkit-background-size", "background-size" ),
1363 ( "-webkit-box-shadow", "box-shadow" ),
1364
1365 # Functions
1366 ( "-webkit-gradient", "gradient" ),
1367 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1368 ( "-webkit-linear-gradient", "linear-gradient" ),
1369 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1370 ( "-webkit-radial-gradient", "radial-gradient" ),
1371 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1372]
1373
1374def _CheckNoDeprecatedCSS(input_api, output_api):
1375 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251376 properties, functions or values. Our external
1377 documentation is ignored by the hooks as it
1378 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531379 results = []
dbeam070cfe62014-10-22 06:44:021380 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251381 black_list = (_EXCLUDED_PATHS +
1382 _TEST_CODE_EXCLUDED_PATHS +
1383 input_api.DEFAULT_BLACK_LIST +
1384 (r"^chrome/common/extensions/docs",
1385 r"^chrome/docs",
1386 r"^native_client_sdk"))
1387 file_filter = lambda f: input_api.FilterSourceFile(
1388 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531389 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1390 for line_num, line in fpath.ChangedContents():
1391 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021392 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531393 results.append(output_api.PresubmitError(
1394 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1395 (fpath.LocalPath(), line_num, deprecated_value, value)))
1396 return results
1397
mohan.reddyf21db962014-10-16 12:26:471398
dbeam070cfe62014-10-22 06:44:021399_DEPRECATED_JS = [
1400 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1401 ( "__defineGetter__", "Object.defineProperty" ),
1402 ( "__defineSetter__", "Object.defineProperty" ),
1403]
1404
1405def _CheckNoDeprecatedJS(input_api, output_api):
1406 """Make sure that we don't use deprecated JS in Chrome code."""
1407 results = []
1408 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1409 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1410 input_api.DEFAULT_BLACK_LIST)
1411 file_filter = lambda f: input_api.FilterSourceFile(
1412 f, white_list=file_inclusion_pattern, black_list=black_list)
1413 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1414 for lnum, line in fpath.ChangedContents():
1415 for (deprecated, replacement) in _DEPRECATED_JS:
1416 if deprecated in line:
1417 results.append(output_api.PresubmitError(
1418 "%s:%d: Use of deprecated JS %s, use %s instead" %
1419 (fpath.LocalPath(), lnum, deprecated, replacement)))
1420 return results
1421
1422
[email protected]22c9bd72011-03-27 16:47:391423def _CommonChecks(input_api, output_api):
1424 """Checks common to both upload and commit."""
1425 results = []
1426 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381427 input_api, output_api,
1428 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461429 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191430 results.extend(
[email protected]760deea2013-12-10 19:33:491431 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541432 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181433 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221434 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441435 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591436 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061437 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121438 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181439 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221440 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491441 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271442 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031443 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491444 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441445 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271446 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541447 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441448 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461449 # TODO(danakj): Remove this when base/move.h is removed.
1450 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551451 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041452 results.extend(
1453 input_api.canned_checks.CheckChangeHasNoTabs(
1454 input_api,
1455 output_api,
1456 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401457 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161458 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591459 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081460 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531461 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021462 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471463 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041464 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361465 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231466 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431467 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241468
1469 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1470 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1471 input_api, output_api,
1472 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381473 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391474 return results
[email protected]1f7b4172010-01-28 01:17:341475
[email protected]b337cb5b2011-01-23 21:24:051476
[email protected]66daa702011-05-28 14:41:461477def _CheckAuthorizedAuthor(input_api, output_api):
1478 """For non-googler/chromites committers, verify the author's email address is
1479 in AUTHORS.
1480 """
[email protected]9bb9cb82011-06-13 20:43:011481 # TODO(maruel): Add it to input_api?
1482 import fnmatch
1483
[email protected]66daa702011-05-28 14:41:461484 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011485 if not author:
1486 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461487 return []
[email protected]c99663292011-05-31 19:46:081488 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461489 input_api.PresubmitLocalPath(), 'AUTHORS')
1490 valid_authors = (
1491 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1492 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181493 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441494 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231495 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461496 return [output_api.PresubmitPromptWarning(
1497 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1498 '\n'
1499 'http://www.chromium.org/developers/contributing-code and read the '
1500 '"Legal" section\n'
1501 'If you are a chromite, verify the contributor signed the CLA.') %
1502 author)]
1503 return []
1504
1505
[email protected]b8079ae4a2012-12-05 19:56:491506def _CheckPatchFiles(input_api, output_api):
1507 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1508 if f.LocalPath().endswith(('.orig', '.rej'))]
1509 if problems:
1510 return [output_api.PresubmitError(
1511 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031512 else:
1513 return []
[email protected]b8079ae4a2012-12-05 19:56:491514
1515
[email protected]b00342e7f2013-03-26 16:21:541516def _DidYouMeanOSMacro(bad_macro):
1517 try:
1518 return {'A': 'OS_ANDROID',
1519 'B': 'OS_BSD',
1520 'C': 'OS_CHROMEOS',
1521 'F': 'OS_FREEBSD',
1522 'L': 'OS_LINUX',
1523 'M': 'OS_MACOSX',
1524 'N': 'OS_NACL',
1525 'O': 'OS_OPENBSD',
1526 'P': 'OS_POSIX',
1527 'S': 'OS_SOLARIS',
1528 'W': 'OS_WIN'}[bad_macro[3].upper()]
1529 except KeyError:
1530 return ''
1531
1532
1533def _CheckForInvalidOSMacrosInFile(input_api, f):
1534 """Check for sensible looking, totally invalid OS macros."""
1535 preprocessor_statement = input_api.re.compile(r'^\s*#')
1536 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1537 results = []
1538 for lnum, line in f.ChangedContents():
1539 if preprocessor_statement.search(line):
1540 for match in os_macro.finditer(line):
1541 if not match.group(1) in _VALID_OS_MACROS:
1542 good = _DidYouMeanOSMacro(match.group(1))
1543 did_you_mean = ' (did you mean %s?)' % good if good else ''
1544 results.append(' %s:%d %s%s' % (f.LocalPath(),
1545 lnum,
1546 match.group(1),
1547 did_you_mean))
1548 return results
1549
1550
1551def _CheckForInvalidOSMacros(input_api, output_api):
1552 """Check all affected files for invalid OS macros."""
1553 bad_macros = []
1554 for f in input_api.AffectedFiles():
1555 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1556 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1557
1558 if not bad_macros:
1559 return []
1560
1561 return [output_api.PresubmitError(
1562 'Possibly invalid OS macro[s] found. Please fix your code\n'
1563 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1564
lliabraa35bab3932014-10-01 12:16:441565
1566def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1567 """Check all affected files for invalid "if defined" macros."""
1568 ALWAYS_DEFINED_MACROS = (
1569 "TARGET_CPU_PPC",
1570 "TARGET_CPU_PPC64",
1571 "TARGET_CPU_68K",
1572 "TARGET_CPU_X86",
1573 "TARGET_CPU_ARM",
1574 "TARGET_CPU_MIPS",
1575 "TARGET_CPU_SPARC",
1576 "TARGET_CPU_ALPHA",
1577 "TARGET_IPHONE_SIMULATOR",
1578 "TARGET_OS_EMBEDDED",
1579 "TARGET_OS_IPHONE",
1580 "TARGET_OS_MAC",
1581 "TARGET_OS_UNIX",
1582 "TARGET_OS_WIN32",
1583 )
1584 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1585 results = []
1586 for lnum, line in f.ChangedContents():
1587 for match in ifdef_macro.finditer(line):
1588 if match.group(1) in ALWAYS_DEFINED_MACROS:
1589 always_defined = ' %s is always defined. ' % match.group(1)
1590 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1591 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1592 lnum,
1593 always_defined,
1594 did_you_mean))
1595 return results
1596
1597
1598def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1599 """Check all affected files for invalid "if defined" macros."""
1600 bad_macros = []
1601 for f in input_api.AffectedFiles():
1602 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1603 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1604
1605 if not bad_macros:
1606 return []
1607
1608 return [output_api.PresubmitError(
1609 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1610 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1611 bad_macros)]
1612
1613
danakj3c84d0c2014-10-06 15:35:461614def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1615 """Check all affected files for using side effects of Pass."""
1616 errors = []
1617 for f in input_api.AffectedFiles():
1618 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1619 for lnum, line in f.ChangedContents():
1620 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471621 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461622 errors.append(output_api.PresubmitError(
1623 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1624 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1625 return errors
1626
1627
mlamouria82272622014-09-16 18:45:041628def _CheckForIPCRules(input_api, output_api):
1629 """Check for same IPC rules described in
1630 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1631 """
1632 base_pattern = r'IPC_ENUM_TRAITS\('
1633 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1634 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1635
1636 problems = []
1637 for f in input_api.AffectedSourceFiles(None):
1638 local_path = f.LocalPath()
1639 if not local_path.endswith('.h'):
1640 continue
1641 for line_number, line in f.ChangedContents():
1642 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1643 problems.append(
1644 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1645
1646 if problems:
1647 return [output_api.PresubmitPromptWarning(
1648 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1649 else:
1650 return []
1651
[email protected]b00342e7f2013-03-26 16:21:541652
mostynbb639aca52015-01-07 20:31:231653def _CheckForWindowsLineEndings(input_api, output_api):
1654 """Check source code and known ascii text files for Windows style line
1655 endings.
1656 """
earthdok1b5e0ee2015-03-10 15:19:101657 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231658
1659 file_inclusion_pattern = (
1660 known_text_files,
1661 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1662 )
1663
1664 filter = lambda f: input_api.FilterSourceFile(
1665 f, white_list=file_inclusion_pattern, black_list=None)
1666 files = [f.LocalPath() for f in
1667 input_api.AffectedSourceFiles(filter)]
1668
1669 problems = []
1670
1671 for file in files:
1672 fp = open(file, 'r')
1673 for line in fp:
1674 if line.endswith('\r\n'):
1675 problems.append(file)
1676 break
1677 fp.close()
1678
1679 if problems:
1680 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1681 'these files to contain Windows style line endings?\n' +
1682 '\n'.join(problems))]
1683
1684 return []
1685
1686
[email protected]1f7b4172010-01-28 01:17:341687def CheckChangeOnUpload(input_api, output_api):
1688 results = []
1689 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471690 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171691 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281692 results.extend(
1693 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191694 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541695 return results
[email protected]ca8d1982009-02-19 16:33:121696
1697
[email protected]1bfb8322014-04-23 01:02:411698def GetTryServerMasterForBot(bot):
1699 """Returns the Try Server master for the given bot.
1700
[email protected]0bb112362014-07-26 04:38:321701 It tries to guess the master from the bot name, but may still fail
1702 and return None. There is no longer a default master.
1703 """
1704 # Potentially ambiguous bot names are listed explicitly.
1705 master_map = {
[email protected]0bb112362014-07-26 04:38:321706 'chromium_presubmit': 'tryserver.chromium.linux',
1707 'blink_presubmit': 'tryserver.chromium.linux',
1708 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411709 }
[email protected]0bb112362014-07-26 04:38:321710 master = master_map.get(bot)
1711 if not master:
sergiyb37fd293f2015-02-26 06:55:011712 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321713 master = 'tryserver.chromium.linux'
1714 elif 'win' in bot:
1715 master = 'tryserver.chromium.win'
1716 elif 'mac' in bot or 'ios' in bot:
1717 master = 'tryserver.chromium.mac'
1718 return master
[email protected]1bfb8322014-04-23 01:02:411719
1720
Paweł Hajdan, Jr55083782014-12-19 20:32:561721def GetDefaultTryConfigs(bots):
1722 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011723 """
1724
Paweł Hajdan, Jr55083782014-12-19 20:32:561725 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411726
1727 # Build up the mapping from tryserver master to bot/test.
1728 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561729 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411730 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1731 return out
[email protected]38c6a512013-12-18 23:48:011732
1733
[email protected]ca8d1982009-02-19 16:33:121734def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541735 results = []
[email protected]1f7b4172010-01-28 01:17:341736 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511737 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1738 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1739 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541740 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271741 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341742 input_api,
1743 output_api,
[email protected]2fdd1f362013-01-16 03:56:031744 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271745
[email protected]3e4eb112011-01-18 03:29:541746 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1747 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411748 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1749 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541750 return results
[email protected]ca8d1982009-02-19 16:33:121751
1752
[email protected]7468ac522014-03-12 23:35:571753def GetPreferredTryMasters(project, change):
mohan.reddyf21db962014-10-16 12:26:471754 import re
[email protected]4ce995ea2012-06-27 02:13:101755 files = change.LocalPaths()
1756
Paweł Hajdan, Jref2afd42015-01-07 15:59:521757 import os
1758 import json
1759 with open(os.path.join(
1760 change.RepositoryRoot(), 'testing', 'commit_queue', 'config.json')) as f:
1761 cq_config = json.load(f)
smut3ef206e12015-03-20 09:30:001762 cq_verifiers = cq_config.get('verifiers_no_patch', {})
1763 cq_try_jobs = cq_verifiers.get('try_job_verifier', {})
1764 builders = cq_try_jobs.get('launched', {})
1765
1766 for master, master_config in cq_try_jobs.get('triggered', {}).iteritems():
Paweł Hajdan, Jref2afd42015-01-07 15:59:521767 for triggered_bot in master_config:
1768 builders.get(master, {}).pop(triggered_bot, None)
[email protected]911753b2012-08-02 12:11:541769
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321770 # Explicitly iterate over copies of dicts since we mutate them.
1771 for master in builders.keys():
1772 for builder in builders[master].keys():
1773 # Do not trigger presubmit builders, since they're likely to fail
1774 # (e.g. OWNERS checks before finished code review), and we're
1775 # running local presubmit anyway.
1776 if 'presubmit' in builder:
1777 builders[master].pop(builder)
1778
Paweł Hajdan, Jref2afd42015-01-07 15:59:521779 return builders