blob: d8f4fd154d87a5a6f2abae5f045456853957f6d3 [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 ),
[email protected]127f18ec2012-06-16 05:05:59253)
254
mlamouria82272622014-09-16 18:45:04255_IPC_ENUM_TRAITS_DEPRECATED = (
256 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
257 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
258
[email protected]127f18ec2012-06-16 05:05:59259
[email protected]b00342e7f2013-03-26 16:21:54260_VALID_OS_MACROS = (
261 # Please keep sorted.
262 'OS_ANDROID',
[email protected]f4440b42014-03-19 05:47:01263 'OS_ANDROID_HOST',
[email protected]b00342e7f2013-03-26 16:21:54264 'OS_BSD',
265 'OS_CAT', # For testing.
266 'OS_CHROMEOS',
267 'OS_FREEBSD',
268 'OS_IOS',
269 'OS_LINUX',
270 'OS_MACOSX',
271 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21272 'OS_NACL_NONSFI',
273 'OS_NACL_SFI',
[email protected]b00342e7f2013-03-26 16:21:54274 'OS_OPENBSD',
275 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37276 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54277 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54278 'OS_WIN',
279)
280
281
[email protected]55459852011-08-10 15:17:19282def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
283 """Attempts to prevent use of functions intended only for testing in
284 non-testing code. For now this is just a best-effort implementation
285 that ignores header files and may have some false positives. A
286 better implementation would probably need a proper C++ parser.
287 """
288 # We only scan .cc files and the like, as the declaration of
289 # for-testing functions in header files are hard to distinguish from
290 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44291 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19292
[email protected]23501822014-05-14 02:06:09293 base_function_pattern = r'[ :]test::[^\s]+|ForTest(ing)?|for_test(ing)?'
[email protected]55459852011-08-10 15:17:19294 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09295 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19296 exclusion_pattern = input_api.re.compile(
297 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
298 base_function_pattern, base_function_pattern))
299
300 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44301 black_list = (_EXCLUDED_PATHS +
302 _TEST_CODE_EXCLUDED_PATHS +
303 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19304 return input_api.FilterSourceFile(
305 affected_file,
306 white_list=(file_inclusion_pattern, ),
307 black_list=black_list)
308
309 problems = []
310 for f in input_api.AffectedSourceFiles(FilterFile):
311 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24312 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03313 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46314 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03315 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19316 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03317 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19318
319 if problems:
[email protected]f7051d52013-04-02 18:31:42320 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03321 else:
322 return []
[email protected]55459852011-08-10 15:17:19323
324
[email protected]10689ca2011-09-02 02:31:54325def _CheckNoIOStreamInHeaders(input_api, output_api):
326 """Checks to make sure no .h files include <iostream>."""
327 files = []
328 pattern = input_api.re.compile(r'^#include\s*<iostream>',
329 input_api.re.MULTILINE)
330 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
331 if not f.LocalPath().endswith('.h'):
332 continue
333 contents = input_api.ReadFile(f)
334 if pattern.search(contents):
335 files.append(f)
336
337 if len(files):
338 return [ output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06339 'Do not #include <iostream> in header files, since it inserts static '
340 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54341 '#include <ostream>. See http://crbug.com/94794',
342 files) ]
343 return []
344
345
[email protected]72df4e782012-06-21 16:28:18346def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
347 """Checks to make sure no source files use UNIT_TEST"""
348 problems = []
349 for f in input_api.AffectedFiles():
350 if (not f.LocalPath().endswith(('.cc', '.mm'))):
351 continue
352
353 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04354 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18355 problems.append(' %s:%d' % (f.LocalPath(), line_num))
356
357 if not problems:
358 return []
359 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
360 '\n'.join(problems))]
361
362
mcasasb7440c282015-02-04 14:52:19363def _FindHistogramNameInLine(histogram_name, line):
364 """Tries to find a histogram name or prefix in a line."""
365 if not "affected-histogram" in line:
366 return histogram_name in line
367 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
368 # the histogram_name.
369 if not '"' in line:
370 return False
371 histogram_prefix = line.split('\"')[1]
372 return histogram_prefix in histogram_name
373
374
375def _CheckUmaHistogramChanges(input_api, output_api):
376 """Check that UMA histogram names in touched lines can still be found in other
377 lines of the patch or in histograms.xml. Note that this check would not catch
378 the reverse: changes in histograms.xml not matched in the code itself."""
379 touched_histograms = []
380 histograms_xml_modifications = []
381 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
382 for f in input_api.AffectedFiles():
383 # If histograms.xml itself is modified, keep the modified lines for later.
384 if f.LocalPath().endswith(('histograms.xml')):
385 histograms_xml_modifications = f.ChangedContents()
386 continue
387 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
388 continue
389 for line_num, line in f.ChangedContents():
390 found = pattern.search(line)
391 if found:
392 touched_histograms.append([found.group(1), f, line_num])
393
394 # Search for the touched histogram names in the local modifications to
395 # histograms.xml, and, if not found, on the base histograms.xml file.
396 unmatched_histograms = []
397 for histogram_info in touched_histograms:
398 histogram_name_found = False
399 for line_num, line in histograms_xml_modifications:
400 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
401 if histogram_name_found:
402 break
403 if not histogram_name_found:
404 unmatched_histograms.append(histogram_info)
405
406 problems = []
407 if unmatched_histograms:
408 with open('tools/metrics/histograms/histograms.xml') as histograms_xml:
409 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45410 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19411 histogram_name_found = False
412 for line in histograms_xml:
413 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
414 if histogram_name_found:
415 break
416 if not histogram_name_found:
417 problems.append(' [%s:%d] %s' %
418 (f.LocalPath(), line_num, histogram_name))
419
420 if not problems:
421 return []
422 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
423 'been modified and the associated histogram name has no match in either '
424 'metrics/histograms.xml or the modifications of it:', problems)]
425
426
[email protected]8ea5d4b2011-09-13 21:49:22427def _CheckNoNewWStrings(input_api, output_api):
428 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27429 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22430 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20431 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57432 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
433 '/win/' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20434 continue
[email protected]8ea5d4b2011-09-13 21:49:22435
[email protected]a11dbe9b2012-08-07 01:32:58436 allowWString = False
[email protected]b5c24292011-11-28 14:38:20437 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58438 if 'presubmit: allow wstring' in line:
439 allowWString = True
440 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27441 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58442 allowWString = False
443 else:
444 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22445
[email protected]55463aa62011-10-12 00:48:27446 if not problems:
447 return []
448 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58449 ' If you are calling a cross-platform API that accepts a wstring, '
450 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27451 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22452
453
[email protected]2a8ac9c2011-10-19 17:20:44454def _CheckNoDEPSGIT(input_api, output_api):
455 """Make sure .DEPS.git is never modified manually."""
456 if any(f.LocalPath().endswith('.DEPS.git') for f in
457 input_api.AffectedFiles()):
458 return [output_api.PresubmitError(
459 'Never commit changes to .DEPS.git. This file is maintained by an\n'
460 'automated system based on what\'s in DEPS and your changes will be\n'
461 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34462 '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:44463 'for more information')]
464 return []
465
466
tandriief664692014-09-23 14:51:47467def _CheckValidHostsInDEPS(input_api, output_api):
468 """Checks that DEPS file deps are from allowed_hosts."""
469 # Run only if DEPS file has been modified to annoy fewer bystanders.
470 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
471 return []
472 # Outsource work to gclient verify
473 try:
474 input_api.subprocess.check_output(['gclient', 'verify'])
475 return []
476 except input_api.subprocess.CalledProcessError, error:
477 return [output_api.PresubmitError(
478 'DEPS file must have only git dependencies.',
479 long_text=error.output)]
480
481
[email protected]127f18ec2012-06-16 05:05:59482def _CheckNoBannedFunctions(input_api, output_api):
483 """Make sure that banned functions are not used."""
484 warnings = []
485 errors = []
486
487 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
488 for f in input_api.AffectedFiles(file_filter=file_filter):
489 for line_num, line in f.ChangedContents():
490 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
[email protected]eaae1972014-04-16 04:17:26491 matched = False
492 if func_name[0:1] == '/':
493 regex = func_name[1:]
494 if input_api.re.search(regex, line):
495 matched = True
496 elif func_name in line:
497 matched = True
498 if matched:
[email protected]127f18ec2012-06-16 05:05:59499 problems = warnings;
500 if error:
501 problems = errors;
502 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
503 for message_line in message:
504 problems.append(' %s' % message_line)
505
506 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
507 for f in input_api.AffectedFiles(file_filter=file_filter):
508 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49509 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
510 def IsBlacklisted(affected_file, blacklist):
511 local_path = affected_file.LocalPath()
512 for item in blacklist:
513 if input_api.re.match(item, local_path):
514 return True
515 return False
516 if IsBlacklisted(f, excluded_paths):
517 continue
[email protected]d89eec82013-12-03 14:10:59518 matched = False
519 if func_name[0:1] == '/':
520 regex = func_name[1:]
521 if input_api.re.search(regex, line):
522 matched = True
523 elif func_name in line:
524 matched = True
525 if matched:
[email protected]127f18ec2012-06-16 05:05:59526 problems = warnings;
527 if error:
528 problems = errors;
529 problems.append(' %s:%d:' % (f.LocalPath(), line_num))
530 for message_line in message:
531 problems.append(' %s' % message_line)
532
533 result = []
534 if (warnings):
535 result.append(output_api.PresubmitPromptWarning(
536 'Banned functions were used.\n' + '\n'.join(warnings)))
537 if (errors):
538 result.append(output_api.PresubmitError(
539 'Banned functions were used.\n' + '\n'.join(errors)))
540 return result
541
542
[email protected]6c063c62012-07-11 19:11:06543def _CheckNoPragmaOnce(input_api, output_api):
544 """Make sure that banned functions are not used."""
545 files = []
546 pattern = input_api.re.compile(r'^#pragma\s+once',
547 input_api.re.MULTILINE)
548 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
549 if not f.LocalPath().endswith('.h'):
550 continue
551 contents = input_api.ReadFile(f)
552 if pattern.search(contents):
553 files.append(f)
554
555 if files:
556 return [output_api.PresubmitError(
557 'Do not use #pragma once in header files.\n'
558 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
559 files)]
560 return []
561
[email protected]127f18ec2012-06-16 05:05:59562
[email protected]e7479052012-09-19 00:26:12563def _CheckNoTrinaryTrueFalse(input_api, output_api):
564 """Checks to make sure we don't introduce use of foo ? true : false."""
565 problems = []
566 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
567 for f in input_api.AffectedFiles():
568 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
569 continue
570
571 for line_num, line in f.ChangedContents():
572 if pattern.match(line):
573 problems.append(' %s:%d' % (f.LocalPath(), line_num))
574
575 if not problems:
576 return []
577 return [output_api.PresubmitPromptWarning(
578 'Please consider avoiding the "? true : false" pattern if possible.\n' +
579 '\n'.join(problems))]
580
581
[email protected]55f9f382012-07-31 11:02:18582def _CheckUnwantedDependencies(input_api, output_api):
583 """Runs checkdeps on #include statements added in this
584 change. Breaking - rules is an error, breaking ! rules is a
585 warning.
586 """
mohan.reddyf21db962014-10-16 12:26:47587 import sys
[email protected]55f9f382012-07-31 11:02:18588 # We need to wait until we have an input_api object and use this
589 # roundabout construct to import checkdeps because this file is
590 # eval-ed and thus doesn't have __file__.
591 original_sys_path = sys.path
592 try:
593 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47594 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18595 import checkdeps
596 from cpp_checker import CppChecker
597 from rules import Rule
598 finally:
599 # Restore sys.path to what it was before.
600 sys.path = original_sys_path
601
602 added_includes = []
603 for f in input_api.AffectedFiles():
604 if not CppChecker.IsCppFile(f.LocalPath()):
605 continue
606
607 changed_lines = [line for line_num, line in f.ChangedContents()]
608 added_includes.append([f.LocalPath(), changed_lines])
609
[email protected]26385172013-05-09 23:11:35610 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18611
612 error_descriptions = []
613 warning_descriptions = []
614 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
615 added_includes):
616 description_with_path = '%s\n %s' % (path, rule_description)
617 if rule_type == Rule.DISALLOW:
618 error_descriptions.append(description_with_path)
619 else:
620 warning_descriptions.append(description_with_path)
621
622 results = []
623 if error_descriptions:
624 results.append(output_api.PresubmitError(
625 'You added one or more #includes that violate checkdeps rules.',
626 error_descriptions))
627 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42628 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18629 'You added one or more #includes of files that are temporarily\n'
630 'allowed but being removed. Can you avoid introducing the\n'
631 '#include? See relevant DEPS file(s) for details and contacts.',
632 warning_descriptions))
633 return results
634
635
[email protected]fbcafe5a2012-08-08 15:31:22636def _CheckFilePermissions(input_api, output_api):
637 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15638 if input_api.platform == 'win32':
639 return []
mohan.reddyf21db962014-10-16 12:26:47640 args = [input_api.python_executable, 'tools/checkperms/checkperms.py',
641 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22642 for f in input_api.AffectedFiles():
643 args += ['--file', f.LocalPath()]
[email protected]f0d330f2014-01-30 01:44:34644 checkperms = input_api.subprocess.Popen(args,
645 stdout=input_api.subprocess.PIPE)
646 errors = checkperms.communicate()[0].strip()
[email protected]fbcafe5a2012-08-08 15:31:22647 if errors:
[email protected]f0d330f2014-01-30 01:44:34648 return [output_api.PresubmitError('checkperms.py failed.',
649 errors.splitlines())]
650 return []
[email protected]fbcafe5a2012-08-08 15:31:22651
652
[email protected]c8278b32012-10-30 20:35:49653def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
654 """Makes sure we don't include ui/aura/window_property.h
655 in header files.
656 """
657 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
658 errors = []
659 for f in input_api.AffectedFiles():
660 if not f.LocalPath().endswith('.h'):
661 continue
662 for line_num, line in f.ChangedContents():
663 if pattern.match(line):
664 errors.append(' %s:%d' % (f.LocalPath(), line_num))
665
666 results = []
667 if errors:
668 results.append(output_api.PresubmitError(
669 'Header files should not include ui/aura/window_property.h', errors))
670 return results
671
672
[email protected]cf9b78f2012-11-14 11:40:28673def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
674 """Checks that the lines in scope occur in the right order.
675
676 1. C system files in alphabetical order
677 2. C++ system files in alphabetical order
678 3. Project's .h files
679 """
680
681 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
682 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
683 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
684
685 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
686
687 state = C_SYSTEM_INCLUDES
688
689 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57690 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28691 problem_linenums = []
692 for line_num, line in scope:
693 if c_system_include_pattern.match(line):
694 if state != C_SYSTEM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57695 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28696 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57697 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28698 elif cpp_system_include_pattern.match(line):
699 if state == C_SYSTEM_INCLUDES:
700 state = CPP_SYSTEM_INCLUDES
701 elif state == CUSTOM_INCLUDES:
[email protected]728b9bb2012-11-14 20:38:57702 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28703 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57704 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28705 elif custom_include_pattern.match(line):
706 if state != CUSTOM_INCLUDES:
707 state = CUSTOM_INCLUDES
708 elif previous_line and previous_line > line:
[email protected]728b9bb2012-11-14 20:38:57709 problem_linenums.append((line_num, previous_line_num))
[email protected]cf9b78f2012-11-14 11:40:28710 else:
711 problem_linenums.append(line_num)
712 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57713 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28714
715 warnings = []
[email protected]728b9bb2012-11-14 20:38:57716 for (line_num, previous_line_num) in problem_linenums:
717 if line_num in changed_linenums or previous_line_num in changed_linenums:
[email protected]cf9b78f2012-11-14 11:40:28718 warnings.append(' %s:%d' % (file_path, line_num))
719 return warnings
720
721
[email protected]ac294a12012-12-06 16:38:43722def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28723 """Checks the #include order for the given file f."""
724
[email protected]2299dcf2012-11-15 19:56:24725 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30726 # Exclude the following includes from the check:
727 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
728 # specific order.
729 # 2) <atlbase.h>, "build/build_config.h"
730 excluded_include_pattern = input_api.re.compile(
731 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24732 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33733 # Match the final or penultimate token if it is xxxtest so we can ignore it
734 # when considering the special first include.
735 test_file_tag_pattern = input_api.re.compile(
736 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11737 if_pattern = input_api.re.compile(
738 r'\s*#\s*(if|elif|else|endif|define|undef).*')
739 # Some files need specialized order of includes; exclude such files from this
740 # check.
741 uncheckable_includes_pattern = input_api.re.compile(
742 r'\s*#include '
743 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28744
745 contents = f.NewContents()
746 warnings = []
747 line_num = 0
748
[email protected]ac294a12012-12-06 16:38:43749 # Handle the special first include. If the first include file is
750 # some/path/file.h, the corresponding including file can be some/path/file.cc,
751 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
752 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33753 # If the included file is some/path/file_platform.h the including file could
754 # also be some/path/file_xxxtest_platform.h.
755 including_file_base_name = test_file_tag_pattern.sub(
756 '', input_api.os_path.basename(f.LocalPath()))
757
[email protected]ac294a12012-12-06 16:38:43758 for line in contents:
759 line_num += 1
760 if system_include_pattern.match(line):
761 # No special first include -> process the line again along with normal
762 # includes.
763 line_num -= 1
764 break
765 match = custom_include_pattern.match(line)
766 if match:
767 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33768 header_basename = test_file_tag_pattern.sub(
769 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
770
771 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24772 # No special first include -> process the line again along with normal
773 # includes.
774 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43775 break
[email protected]cf9b78f2012-11-14 11:40:28776
777 # Split into scopes: Each region between #if and #endif is its own scope.
778 scopes = []
779 current_scope = []
780 for line in contents[line_num:]:
781 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11782 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54783 continue
[email protected]2309b0fa02012-11-16 12:18:27784 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28785 scopes.append(current_scope)
786 current_scope = []
[email protected]962f117e2012-11-22 18:11:56787 elif ((system_include_pattern.match(line) or
788 custom_include_pattern.match(line)) and
789 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28790 current_scope.append((line_num, line))
791 scopes.append(current_scope)
792
793 for scope in scopes:
794 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
795 changed_linenums))
796 return warnings
797
798
799def _CheckIncludeOrder(input_api, output_api):
800 """Checks that the #include order is correct.
801
802 1. The corresponding header for source files.
803 2. C system files in alphabetical order
804 3. C++ system files in alphabetical order
805 4. Project's .h files in alphabetical order
806
[email protected]ac294a12012-12-06 16:38:43807 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
808 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28809 """
[email protected]e120b012014-08-15 19:08:35810 def FileFilterIncludeOrder(affected_file):
811 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
812 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28813
814 warnings = []
[email protected]e120b012014-08-15 19:08:35815 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
[email protected]ac294a12012-12-06 16:38:43816 if f.LocalPath().endswith(('.cc', '.h')):
817 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
818 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28819
820 results = []
821 if warnings:
[email protected]f7051d52013-04-02 18:31:42822 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53823 warnings))
[email protected]cf9b78f2012-11-14 11:40:28824 return results
825
826
[email protected]70ca77752012-11-20 03:45:03827def _CheckForVersionControlConflictsInFile(input_api, f):
828 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
829 errors = []
830 for line_num, line in f.ChangedContents():
831 if pattern.match(line):
832 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
833 return errors
834
835
836def _CheckForVersionControlConflicts(input_api, output_api):
837 """Usually this is not intentional and will cause a compile failure."""
838 errors = []
839 for f in input_api.AffectedFiles():
840 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
841
842 results = []
843 if errors:
844 results.append(output_api.PresubmitError(
845 'Version control conflict markers found, please resolve.', errors))
846 return results
847
848
[email protected]06e6d0ff2012-12-11 01:36:44849def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
850 def FilterFile(affected_file):
851 """Filter function for use with input_api.AffectedSourceFiles,
852 below. This filters out everything except non-test files from
853 top-level directories that generally speaking should not hard-code
854 service URLs (e.g. src/android_webview/, src/content/ and others).
855 """
856 return input_api.FilterSourceFile(
857 affected_file,
[email protected]78bb39d62012-12-11 15:11:56858 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44859 black_list=(_EXCLUDED_PATHS +
860 _TEST_CODE_EXCLUDED_PATHS +
861 input_api.DEFAULT_BLACK_LIST))
862
[email protected]de4f7d22013-05-23 14:27:46863 base_pattern = '"[^"]*google\.com[^"]*"'
864 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
865 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44866 problems = [] # items are (filename, line_number, line)
867 for f in input_api.AffectedSourceFiles(FilterFile):
868 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46869 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44870 problems.append((f.LocalPath(), line_num, line))
871
872 if problems:
[email protected]f7051d52013-04-02 18:31:42873 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44874 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58875 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44876 [' %s:%d: %s' % (
877 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03878 else:
879 return []
[email protected]06e6d0ff2012-12-11 01:36:44880
881
[email protected]d2530012013-01-25 16:39:27882def _CheckNoAbbreviationInPngFileName(input_api, output_api):
883 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31884 The native_client_sdk directory is excluded because it has auto-generated PNG
885 files for documentation.
[email protected]d2530012013-01-25 16:39:27886 """
[email protected]d2530012013-01-25 16:39:27887 errors = []
binji0dcdf342014-12-12 18:32:31888 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
889 black_list = (r'^native_client_sdk[\\\/]',)
890 file_filter = lambda f: input_api.FilterSourceFile(
891 f, white_list=white_list, black_list=black_list)
892 for f in input_api.AffectedFiles(include_deletes=False,
893 file_filter=file_filter):
894 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27895
896 results = []
897 if errors:
898 results.append(output_api.PresubmitError(
899 'The name of PNG files should not have abbreviations. \n'
900 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
901 'Contact [email protected] if you have questions.', errors))
902 return results
903
904
[email protected]14a6131c2014-01-08 01:15:41905def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:08906 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:41907 a set of DEPS entries that we should look up.
908
909 For a directory (rather than a specific filename) we fake a path to
910 a specific filename by adding /DEPS. This is chosen as a file that
911 will seldom or never be subject to per-file include_rules.
912 """
[email protected]2b438d62013-11-14 17:54:14913 # We ignore deps entries on auto-generated directories.
914 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:08915
916 # This pattern grabs the path without basename in the first
917 # parentheses, and the basename (if present) in the second. It
918 # relies on the simple heuristic that if there is a basename it will
919 # be a header file ending in ".h".
920 pattern = re.compile(
921 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:14922 results = set()
[email protected]f32e2d1e2013-07-26 21:39:08923 for changed_line in changed_lines:
924 m = pattern.match(changed_line)
925 if m:
926 path = m.group(1)
[email protected]2b438d62013-11-14 17:54:14927 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
[email protected]14a6131c2014-01-08 01:15:41928 if m.group(2):
929 results.add('%s%s' % (path, m.group(2)))
930 else:
931 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:08932 return results
933
934
[email protected]e871964c2013-05-13 14:14:55935def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
936 """When a dependency prefixed with + is added to a DEPS file, we
937 want to make sure that the change is reviewed by an OWNER of the
938 target file or directory, to avoid layering violations from being
939 introduced. This check verifies that this happens.
940 """
941 changed_lines = set()
942 for f in input_api.AffectedFiles():
943 filename = input_api.os_path.basename(f.LocalPath())
944 if filename == 'DEPS':
945 changed_lines |= set(line.strip()
946 for line_num, line
947 in f.ChangedContents())
948 if not changed_lines:
949 return []
950
[email protected]14a6131c2014-01-08 01:15:41951 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
952 changed_lines)
[email protected]e871964c2013-05-13 14:14:55953 if not virtual_depended_on_files:
954 return []
955
956 if input_api.is_committing:
957 if input_api.tbr:
958 return [output_api.PresubmitNotifyResult(
959 '--tbr was specified, skipping OWNERS check for DEPS additions')]
960 if not input_api.change.issue:
961 return [output_api.PresubmitError(
962 "DEPS approval by OWNERS check failed: this change has "
963 "no Rietveld issue number, so we can't check it for approvals.")]
964 output = output_api.PresubmitError
965 else:
966 output = output_api.PresubmitNotifyResult
967
968 owners_db = input_api.owners_db
969 owner_email, reviewers = input_api.canned_checks._RietveldOwnerAndReviewers(
970 input_api,
971 owners_db.email_regexp,
972 approval_needed=input_api.is_committing)
973
974 owner_email = owner_email or input_api.change.author_email
975
[email protected]de4f7d22013-05-23 14:27:46976 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:51977 if owner_email:
[email protected]de4f7d22013-05-23 14:27:46978 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:55979 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
980 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:41981
982 # We strip the /DEPS part that was added by
983 # _FilesToCheckForIncomingDeps to fake a path to a file in a
984 # directory.
985 def StripDeps(path):
986 start_deps = path.rfind('/DEPS')
987 if start_deps != -1:
988 return path[:start_deps]
989 else:
990 return path
991 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:55992 for path in missing_files]
993
994 if unapproved_dependencies:
995 output_list = [
[email protected]14a6131c2014-01-08 01:15:41996 output('Missing LGTM from OWNERS of dependencies added to DEPS:\n %s' %
[email protected]e871964c2013-05-13 14:14:55997 '\n '.join(sorted(unapproved_dependencies)))]
998 if not input_api.is_committing:
999 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1000 output_list.append(output(
1001 'Suggested missing target path OWNERS:\n %s' %
1002 '\n '.join(suggested_owners or [])))
1003 return output_list
1004
1005 return []
1006
1007
[email protected]85218562013-11-22 07:41:401008def _CheckSpamLogging(input_api, output_api):
1009 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1010 black_list = (_EXCLUDED_PATHS +
1011 _TEST_CODE_EXCLUDED_PATHS +
1012 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501013 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191014 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481015 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461016 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121017 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1018 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581019 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161020 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031021 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151022 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1023 r"^chromecast[\\\/]",
1024 r"^cloud_print[\\\/]",
[email protected]9056e732014-01-08 06:25:251025 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1026 r"gl_helper_benchmark\.cc$",
thestigc9e38a22014-09-13 01:02:111027 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151028 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111029 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521030 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501031 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361032 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311033 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131034 r"^tools[\\\/]",
thestig22dfc4012014-09-05 08:29:441035 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
vchigrin14251492015-01-12 08:09:021036 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
thestig22dfc4012014-09-05 08:29:441037 r"dump_file_system.cc$",))
[email protected]85218562013-11-22 07:41:401038 source_file_filter = lambda x: input_api.FilterSourceFile(
1039 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1040
1041 log_info = []
1042 printf = []
1043
1044 for f in input_api.AffectedSourceFiles(source_file_filter):
1045 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471046 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401047 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471048 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131049 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371050
mohan.reddyf21db962014-10-16 12:26:471051 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371052 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471053 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401054 printf.append(f.LocalPath())
1055
1056 if log_info:
1057 return [output_api.PresubmitError(
1058 'These files spam the console log with LOG(INFO):',
1059 items=log_info)]
1060 if printf:
1061 return [output_api.PresubmitError(
1062 'These files spam the console log with printf/fprintf:',
1063 items=printf)]
1064 return []
1065
1066
[email protected]49aa76a2013-12-04 06:59:161067def _CheckForAnonymousVariables(input_api, output_api):
1068 """These types are all expected to hold locks while in scope and
1069 so should never be anonymous (which causes them to be immediately
1070 destroyed)."""
1071 they_who_must_be_named = [
1072 'base::AutoLock',
1073 'base::AutoReset',
1074 'base::AutoUnlock',
1075 'SkAutoAlphaRestore',
1076 'SkAutoBitmapShaderInstall',
1077 'SkAutoBlitterChoose',
1078 'SkAutoBounderCommit',
1079 'SkAutoCallProc',
1080 'SkAutoCanvasRestore',
1081 'SkAutoCommentBlock',
1082 'SkAutoDescriptor',
1083 'SkAutoDisableDirectionCheck',
1084 'SkAutoDisableOvalCheck',
1085 'SkAutoFree',
1086 'SkAutoGlyphCache',
1087 'SkAutoHDC',
1088 'SkAutoLockColors',
1089 'SkAutoLockPixels',
1090 'SkAutoMalloc',
1091 'SkAutoMaskFreeImage',
1092 'SkAutoMutexAcquire',
1093 'SkAutoPathBoundsUpdate',
1094 'SkAutoPDFRelease',
1095 'SkAutoRasterClipValidate',
1096 'SkAutoRef',
1097 'SkAutoTime',
1098 'SkAutoTrace',
1099 'SkAutoUnref',
1100 ]
1101 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1102 # bad: base::AutoLock(lock.get());
1103 # not bad: base::AutoLock lock(lock.get());
1104 bad_pattern = input_api.re.compile(anonymous)
1105 # good: new base::AutoLock(lock.get())
1106 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1107 errors = []
1108
1109 for f in input_api.AffectedFiles():
1110 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1111 continue
1112 for linenum, line in f.ChangedContents():
1113 if bad_pattern.search(line) and not good_pattern.search(line):
1114 errors.append('%s:%d' % (f.LocalPath(), linenum))
1115
1116 if errors:
1117 return [output_api.PresubmitError(
1118 'These lines create anonymous variables that need to be named:',
1119 items=errors)]
1120 return []
1121
1122
[email protected]5fe0f8742013-11-29 01:04:591123def _CheckCygwinShell(input_api, output_api):
1124 source_file_filter = lambda x: input_api.FilterSourceFile(
1125 x, white_list=(r'.+\.(gyp|gypi)$',))
1126 cygwin_shell = []
1127
1128 for f in input_api.AffectedSourceFiles(source_file_filter):
1129 for linenum, line in f.ChangedContents():
1130 if 'msvs_cygwin_shell' in line:
1131 cygwin_shell.append(f.LocalPath())
1132 break
1133
1134 if cygwin_shell:
1135 return [output_api.PresubmitError(
1136 'These files should not use msvs_cygwin_shell (the default is 0):',
1137 items=cygwin_shell)]
1138 return []
1139
[email protected]85218562013-11-22 07:41:401140
[email protected]999261d2014-03-03 20:08:081141def _CheckUserActionUpdate(input_api, output_api):
1142 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521143 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081144 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521145 # If actions.xml is already included in the changelist, the PRESUBMIT
1146 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081147 return []
1148
[email protected]999261d2014-03-03 20:08:081149 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1150 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521151 current_actions = None
[email protected]999261d2014-03-03 20:08:081152 for f in input_api.AffectedFiles(file_filter=file_filter):
1153 for line_num, line in f.ChangedContents():
1154 match = input_api.re.search(action_re, line)
1155 if match:
[email protected]2f92dec2014-03-07 19:21:521156 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1157 # loaded only once.
1158 if not current_actions:
1159 with open('tools/metrics/actions/actions.xml') as actions_f:
1160 current_actions = actions_f.read()
1161 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081162 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521163 action = 'name="{0}"'.format(action_name)
1164 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081165 return [output_api.PresubmitPromptWarning(
1166 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521167 'tools/metrics/actions/actions.xml. Please run '
1168 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081169 % (f.LocalPath(), line_num, action_name))]
1170 return []
1171
1172
[email protected]99171a92014-06-03 08:44:471173def _GetJSONParseError(input_api, filename, eat_comments=True):
1174 try:
1175 contents = input_api.ReadFile(filename)
1176 if eat_comments:
1177 json_comment_eater = input_api.os_path.join(
1178 input_api.PresubmitLocalPath(),
1179 'tools', 'json_comment_eater', 'json_comment_eater.py')
1180 process = input_api.subprocess.Popen(
1181 [input_api.python_executable, json_comment_eater],
1182 stdin=input_api.subprocess.PIPE,
1183 stdout=input_api.subprocess.PIPE,
1184 universal_newlines=True)
1185 (contents, _) = process.communicate(input=contents)
1186
1187 input_api.json.loads(contents)
1188 except ValueError as e:
1189 return e
1190 return None
1191
1192
1193def _GetIDLParseError(input_api, filename):
1194 try:
1195 contents = input_api.ReadFile(filename)
1196 idl_schema = input_api.os_path.join(
1197 input_api.PresubmitLocalPath(),
1198 'tools', 'json_schema_compiler', 'idl_schema.py')
1199 process = input_api.subprocess.Popen(
1200 [input_api.python_executable, idl_schema],
1201 stdin=input_api.subprocess.PIPE,
1202 stdout=input_api.subprocess.PIPE,
1203 stderr=input_api.subprocess.PIPE,
1204 universal_newlines=True)
1205 (_, error) = process.communicate(input=contents)
1206 return error or None
1207 except ValueError as e:
1208 return e
1209
1210
1211def _CheckParseErrors(input_api, output_api):
1212 """Check that IDL and JSON files do not contain syntax errors."""
1213 actions = {
1214 '.idl': _GetIDLParseError,
1215 '.json': _GetJSONParseError,
1216 }
1217 # These paths contain test data and other known invalid JSON files.
1218 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491219 r'test[\\\/]data[\\\/]',
1220 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471221 ]
1222 # Most JSON files are preprocessed and support comments, but these do not.
1223 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491224 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471225 ]
1226 # Only run IDL checker on files in these directories.
1227 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491228 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1229 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471230 ]
1231
1232 def get_action(affected_file):
1233 filename = affected_file.LocalPath()
1234 return actions.get(input_api.os_path.splitext(filename)[1])
1235
1236 def MatchesFile(patterns, path):
1237 for pattern in patterns:
1238 if input_api.re.search(pattern, path):
1239 return True
1240 return False
1241
1242 def FilterFile(affected_file):
1243 action = get_action(affected_file)
1244 if not action:
1245 return False
1246 path = affected_file.LocalPath()
1247
1248 if MatchesFile(excluded_patterns, path):
1249 return False
1250
1251 if (action == _GetIDLParseError and
1252 not MatchesFile(idl_included_patterns, path)):
1253 return False
1254 return True
1255
1256 results = []
1257 for affected_file in input_api.AffectedFiles(
1258 file_filter=FilterFile, include_deletes=False):
1259 action = get_action(affected_file)
1260 kwargs = {}
1261 if (action == _GetJSONParseError and
1262 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1263 kwargs['eat_comments'] = False
1264 parse_error = action(input_api,
1265 affected_file.AbsoluteLocalPath(),
1266 **kwargs)
1267 if parse_error:
1268 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1269 (affected_file.LocalPath(), parse_error)))
1270 return results
1271
1272
[email protected]760deea2013-12-10 19:33:491273def _CheckJavaStyle(input_api, output_api):
1274 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471275 import sys
[email protected]760deea2013-12-10 19:33:491276 original_sys_path = sys.path
1277 try:
1278 sys.path = sys.path + [input_api.os_path.join(
1279 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1280 import checkstyle
1281 finally:
1282 # Restore sys.path to what it was before.
1283 sys.path = original_sys_path
1284
1285 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091286 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511287 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491288
1289
mnaganov9b9b1fe82014-12-11 16:30:361290def _CheckForCopyrightedCode(input_api, output_api):
1291 """Verifies that newly added code doesn't contain copyrighted material
1292 and is properly licensed under the standard Chromium license.
1293
1294 As there can be false positives, we maintain a whitelist file. This check
1295 also verifies that the whitelist file is up to date.
1296 """
1297 import sys
1298 original_sys_path = sys.path
1299 try:
1300 sys.path = sys.path + [input_api.os_path.join(
1301 input_api.PresubmitLocalPath(), 'android_webview', 'tools')]
1302 import copyright_scanner
1303 finally:
1304 # Restore sys.path to what it was before.
1305 sys.path = original_sys_path
1306
1307 return copyright_scanner.ScanAtPresubmit(input_api, output_api)
1308
1309
glidere61efad2015-02-18 17:39:431310def _CheckSingletonInHeaders(input_api, output_api):
1311 """Checks to make sure no header files have |Singleton<|."""
1312 def FileFilter(affected_file):
1313 # It's ok for base/memory/singleton.h to have |Singleton<|.
1314 black_list = (_EXCLUDED_PATHS +
1315 input_api.DEFAULT_BLACK_LIST +
1316 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1317 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1318
1319 pattern = input_api.re.compile(r'(?<!class\s)Singleton\s*<')
1320 files = []
1321 for f in input_api.AffectedSourceFiles(FileFilter):
1322 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1323 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1324 contents = input_api.ReadFile(f)
1325 for line in contents.splitlines(False):
1326 if (not input_api.re.match(r'//', line) and # Strip C++ comment.
1327 pattern.search(line)):
1328 files.append(f)
1329 break
1330
1331 if files:
1332 return [ output_api.PresubmitError(
1333 'Found Singleton<T> in the following header files.\n' +
1334 'Please move them to an appropriate source file so that the ' +
1335 'template gets instantiated in a single compilation unit.',
1336 files) ]
1337 return []
1338
1339
[email protected]fd20b902014-05-09 02:14:531340_DEPRECATED_CSS = [
1341 # Values
1342 ( "-webkit-box", "flex" ),
1343 ( "-webkit-inline-box", "inline-flex" ),
1344 ( "-webkit-flex", "flex" ),
1345 ( "-webkit-inline-flex", "inline-flex" ),
1346 ( "-webkit-min-content", "min-content" ),
1347 ( "-webkit-max-content", "max-content" ),
1348
1349 # Properties
1350 ( "-webkit-background-clip", "background-clip" ),
1351 ( "-webkit-background-origin", "background-origin" ),
1352 ( "-webkit-background-size", "background-size" ),
1353 ( "-webkit-box-shadow", "box-shadow" ),
1354
1355 # Functions
1356 ( "-webkit-gradient", "gradient" ),
1357 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1358 ( "-webkit-linear-gradient", "linear-gradient" ),
1359 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1360 ( "-webkit-radial-gradient", "radial-gradient" ),
1361 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1362]
1363
1364def _CheckNoDeprecatedCSS(input_api, output_api):
1365 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251366 properties, functions or values. Our external
1367 documentation is ignored by the hooks as it
1368 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531369 results = []
dbeam070cfe62014-10-22 06:44:021370 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251371 black_list = (_EXCLUDED_PATHS +
1372 _TEST_CODE_EXCLUDED_PATHS +
1373 input_api.DEFAULT_BLACK_LIST +
1374 (r"^chrome/common/extensions/docs",
1375 r"^chrome/docs",
1376 r"^native_client_sdk"))
1377 file_filter = lambda f: input_api.FilterSourceFile(
1378 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531379 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1380 for line_num, line in fpath.ChangedContents():
1381 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021382 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531383 results.append(output_api.PresubmitError(
1384 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1385 (fpath.LocalPath(), line_num, deprecated_value, value)))
1386 return results
1387
mohan.reddyf21db962014-10-16 12:26:471388
dbeam070cfe62014-10-22 06:44:021389_DEPRECATED_JS = [
1390 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1391 ( "__defineGetter__", "Object.defineProperty" ),
1392 ( "__defineSetter__", "Object.defineProperty" ),
1393]
1394
1395def _CheckNoDeprecatedJS(input_api, output_api):
1396 """Make sure that we don't use deprecated JS in Chrome code."""
1397 results = []
1398 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1399 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1400 input_api.DEFAULT_BLACK_LIST)
1401 file_filter = lambda f: input_api.FilterSourceFile(
1402 f, white_list=file_inclusion_pattern, black_list=black_list)
1403 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1404 for lnum, line in fpath.ChangedContents():
1405 for (deprecated, replacement) in _DEPRECATED_JS:
1406 if deprecated in line:
1407 results.append(output_api.PresubmitError(
1408 "%s:%d: Use of deprecated JS %s, use %s instead" %
1409 (fpath.LocalPath(), lnum, deprecated, replacement)))
1410 return results
1411
1412
[email protected]22c9bd72011-03-27 16:47:391413def _CommonChecks(input_api, output_api):
1414 """Checks common to both upload and commit."""
1415 results = []
1416 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:381417 input_api, output_api,
1418 excluded_paths=_EXCLUDED_PATHS + _TESTRUNNER_PATHS))
[email protected]66daa702011-05-28 14:41:461419 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:191420 results.extend(
[email protected]760deea2013-12-10 19:33:491421 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:541422 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:181423 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:221424 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:441425 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:591426 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:061427 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:121428 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:181429 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:221430 results.extend(_CheckFilePermissions(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:491431 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:271432 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:031433 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:491434 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:441435 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:271436 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:541437 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:441438 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
danakj3c84d0c2014-10-06 15:35:461439 # TODO(danakj): Remove this when base/move.h is removed.
1440 results.extend(_CheckForUsingSideEffectsOfPass(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:551441 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:041442 results.extend(
1443 input_api.canned_checks.CheckChangeHasNoTabs(
1444 input_api,
1445 output_api,
1446 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:401447 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:161448 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:591449 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:081450 results.extend(_CheckUserActionUpdate(input_api, output_api))
[email protected]fd20b902014-05-09 02:14:531451 results.extend(_CheckNoDeprecatedCSS(input_api, output_api))
dbeam070cfe62014-10-22 06:44:021452 results.extend(_CheckNoDeprecatedJS(input_api, output_api))
[email protected]99171a92014-06-03 08:44:471453 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:041454 results.extend(_CheckForIPCRules(input_api, output_api))
mnaganov9b9b1fe82014-12-11 16:30:361455 results.extend(_CheckForCopyrightedCode(input_api, output_api))
mostynbb639aca52015-01-07 20:31:231456 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:431457 results.extend(_CheckSingletonInHeaders(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:241458
1459 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
1460 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
1461 input_api, output_api,
1462 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:381463 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:391464 return results
[email protected]1f7b4172010-01-28 01:17:341465
[email protected]b337cb5b2011-01-23 21:24:051466
[email protected]66daa702011-05-28 14:41:461467def _CheckAuthorizedAuthor(input_api, output_api):
1468 """For non-googler/chromites committers, verify the author's email address is
1469 in AUTHORS.
1470 """
[email protected]9bb9cb82011-06-13 20:43:011471 # TODO(maruel): Add it to input_api?
1472 import fnmatch
1473
[email protected]66daa702011-05-28 14:41:461474 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:011475 if not author:
1476 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:461477 return []
[email protected]c99663292011-05-31 19:46:081478 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:461479 input_api.PresubmitLocalPath(), 'AUTHORS')
1480 valid_authors = (
1481 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
1482 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:181483 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]d8b50be2011-06-15 14:19:441484 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]5861efb2013-01-07 18:33:231485 input_api.logging.info('Valid authors are %s', ', '.join(valid_authors))
[email protected]66daa702011-05-28 14:41:461486 return [output_api.PresubmitPromptWarning(
1487 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
1488 '\n'
1489 'http://www.chromium.org/developers/contributing-code and read the '
1490 '"Legal" section\n'
1491 'If you are a chromite, verify the contributor signed the CLA.') %
1492 author)]
1493 return []
1494
1495
[email protected]b8079ae4a2012-12-05 19:56:491496def _CheckPatchFiles(input_api, output_api):
1497 problems = [f.LocalPath() for f in input_api.AffectedFiles()
1498 if f.LocalPath().endswith(('.orig', '.rej'))]
1499 if problems:
1500 return [output_api.PresubmitError(
1501 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:031502 else:
1503 return []
[email protected]b8079ae4a2012-12-05 19:56:491504
1505
[email protected]b00342e7f2013-03-26 16:21:541506def _DidYouMeanOSMacro(bad_macro):
1507 try:
1508 return {'A': 'OS_ANDROID',
1509 'B': 'OS_BSD',
1510 'C': 'OS_CHROMEOS',
1511 'F': 'OS_FREEBSD',
1512 'L': 'OS_LINUX',
1513 'M': 'OS_MACOSX',
1514 'N': 'OS_NACL',
1515 'O': 'OS_OPENBSD',
1516 'P': 'OS_POSIX',
1517 'S': 'OS_SOLARIS',
1518 'W': 'OS_WIN'}[bad_macro[3].upper()]
1519 except KeyError:
1520 return ''
1521
1522
1523def _CheckForInvalidOSMacrosInFile(input_api, f):
1524 """Check for sensible looking, totally invalid OS macros."""
1525 preprocessor_statement = input_api.re.compile(r'^\s*#')
1526 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
1527 results = []
1528 for lnum, line in f.ChangedContents():
1529 if preprocessor_statement.search(line):
1530 for match in os_macro.finditer(line):
1531 if not match.group(1) in _VALID_OS_MACROS:
1532 good = _DidYouMeanOSMacro(match.group(1))
1533 did_you_mean = ' (did you mean %s?)' % good if good else ''
1534 results.append(' %s:%d %s%s' % (f.LocalPath(),
1535 lnum,
1536 match.group(1),
1537 did_you_mean))
1538 return results
1539
1540
1541def _CheckForInvalidOSMacros(input_api, output_api):
1542 """Check all affected files for invalid OS macros."""
1543 bad_macros = []
1544 for f in input_api.AffectedFiles():
1545 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css')):
1546 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
1547
1548 if not bad_macros:
1549 return []
1550
1551 return [output_api.PresubmitError(
1552 'Possibly invalid OS macro[s] found. Please fix your code\n'
1553 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
1554
lliabraa35bab3932014-10-01 12:16:441555
1556def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
1557 """Check all affected files for invalid "if defined" macros."""
1558 ALWAYS_DEFINED_MACROS = (
1559 "TARGET_CPU_PPC",
1560 "TARGET_CPU_PPC64",
1561 "TARGET_CPU_68K",
1562 "TARGET_CPU_X86",
1563 "TARGET_CPU_ARM",
1564 "TARGET_CPU_MIPS",
1565 "TARGET_CPU_SPARC",
1566 "TARGET_CPU_ALPHA",
1567 "TARGET_IPHONE_SIMULATOR",
1568 "TARGET_OS_EMBEDDED",
1569 "TARGET_OS_IPHONE",
1570 "TARGET_OS_MAC",
1571 "TARGET_OS_UNIX",
1572 "TARGET_OS_WIN32",
1573 )
1574 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
1575 results = []
1576 for lnum, line in f.ChangedContents():
1577 for match in ifdef_macro.finditer(line):
1578 if match.group(1) in ALWAYS_DEFINED_MACROS:
1579 always_defined = ' %s is always defined. ' % match.group(1)
1580 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
1581 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
1582 lnum,
1583 always_defined,
1584 did_you_mean))
1585 return results
1586
1587
1588def _CheckForInvalidIfDefinedMacros(input_api, output_api):
1589 """Check all affected files for invalid "if defined" macros."""
1590 bad_macros = []
1591 for f in input_api.AffectedFiles():
1592 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1593 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
1594
1595 if not bad_macros:
1596 return []
1597
1598 return [output_api.PresubmitError(
1599 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
1600 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
1601 bad_macros)]
1602
1603
danakj3c84d0c2014-10-06 15:35:461604def _CheckForUsingSideEffectsOfPass(input_api, output_api):
1605 """Check all affected files for using side effects of Pass."""
1606 errors = []
1607 for f in input_api.AffectedFiles():
1608 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
1609 for lnum, line in f.ChangedContents():
1610 # Disallow Foo(*my_scoped_thing.Pass()); See crbug.com/418297.
mohan.reddyf21db962014-10-16 12:26:471611 if input_api.re.search(r'\*[a-zA-Z0-9_]+\.Pass\(\)', line):
danakj3c84d0c2014-10-06 15:35:461612 errors.append(output_api.PresubmitError(
1613 ('%s:%d uses *foo.Pass() to delete the contents of scoped_ptr. ' +
1614 'See crbug.com/418297.') % (f.LocalPath(), lnum)))
1615 return errors
1616
1617
mlamouria82272622014-09-16 18:45:041618def _CheckForIPCRules(input_api, output_api):
1619 """Check for same IPC rules described in
1620 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
1621 """
1622 base_pattern = r'IPC_ENUM_TRAITS\('
1623 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
1624 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
1625
1626 problems = []
1627 for f in input_api.AffectedSourceFiles(None):
1628 local_path = f.LocalPath()
1629 if not local_path.endswith('.h'):
1630 continue
1631 for line_number, line in f.ChangedContents():
1632 if inclusion_pattern.search(line) and not comment_pattern.search(line):
1633 problems.append(
1634 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1635
1636 if problems:
1637 return [output_api.PresubmitPromptWarning(
1638 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
1639 else:
1640 return []
1641
[email protected]b00342e7f2013-03-26 16:21:541642
mostynbb639aca52015-01-07 20:31:231643def _CheckForWindowsLineEndings(input_api, output_api):
1644 """Check source code and known ascii text files for Windows style line
1645 endings.
1646 """
earthdok1b5e0ee2015-03-10 15:19:101647 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:231648
1649 file_inclusion_pattern = (
1650 known_text_files,
1651 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1652 )
1653
1654 filter = lambda f: input_api.FilterSourceFile(
1655 f, white_list=file_inclusion_pattern, black_list=None)
1656 files = [f.LocalPath() for f in
1657 input_api.AffectedSourceFiles(filter)]
1658
1659 problems = []
1660
1661 for file in files:
1662 fp = open(file, 'r')
1663 for line in fp:
1664 if line.endswith('\r\n'):
1665 problems.append(file)
1666 break
1667 fp.close()
1668
1669 if problems:
1670 return [output_api.PresubmitPromptWarning('Are you sure that you want '
1671 'these files to contain Windows style line endings?\n' +
1672 '\n'.join(problems))]
1673
1674 return []
1675
1676
[email protected]1f7b4172010-01-28 01:17:341677def CheckChangeOnUpload(input_api, output_api):
1678 results = []
1679 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:471680 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
aurimas8d3bc1c52014-10-15 01:02:171681 results.extend(_CheckJavaStyle(input_api, output_api))
scottmg39b29952014-12-08 18:31:281682 results.extend(
1683 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:191684 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541685 return results
[email protected]ca8d1982009-02-19 16:33:121686
1687
[email protected]1bfb8322014-04-23 01:02:411688def GetTryServerMasterForBot(bot):
1689 """Returns the Try Server master for the given bot.
1690
[email protected]0bb112362014-07-26 04:38:321691 It tries to guess the master from the bot name, but may still fail
1692 and return None. There is no longer a default master.
1693 """
1694 # Potentially ambiguous bot names are listed explicitly.
1695 master_map = {
[email protected]0bb112362014-07-26 04:38:321696 'chromium_presubmit': 'tryserver.chromium.linux',
1697 'blink_presubmit': 'tryserver.chromium.linux',
1698 'tools_build_presubmit': 'tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:411699 }
[email protected]0bb112362014-07-26 04:38:321700 master = master_map.get(bot)
1701 if not master:
sergiyb37fd293f2015-02-26 06:55:011702 if 'linux' in bot or 'android' in bot or 'presubmit' in bot:
[email protected]0bb112362014-07-26 04:38:321703 master = 'tryserver.chromium.linux'
1704 elif 'win' in bot:
1705 master = 'tryserver.chromium.win'
1706 elif 'mac' in bot or 'ios' in bot:
1707 master = 'tryserver.chromium.mac'
1708 return master
[email protected]1bfb8322014-04-23 01:02:411709
1710
Paweł Hajdan, Jr55083782014-12-19 20:32:561711def GetDefaultTryConfigs(bots):
1712 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:011713 """
1714
Paweł Hajdan, Jr55083782014-12-19 20:32:561715 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:411716
1717 # Build up the mapping from tryserver master to bot/test.
1718 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:561719 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:411720 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
1721 return out
[email protected]38c6a512013-12-18 23:48:011722
1723
[email protected]ca8d1982009-02-19 16:33:121724def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:541725 results = []
[email protected]1f7b4172010-01-28 01:17:341726 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:511727 # TODO(thestig) temporarily disabled, doesn't work in third_party/
1728 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
1729 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:541730 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:271731 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:341732 input_api,
1733 output_api,
[email protected]2fdd1f362013-01-16 03:56:031734 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:271735
[email protected]3e4eb112011-01-18 03:29:541736 results.extend(input_api.canned_checks.CheckChangeHasBugField(
1737 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:411738 results.extend(input_api.canned_checks.CheckChangeHasDescription(
1739 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:541740 return results
[email protected]ca8d1982009-02-19 16:33:121741
1742
[email protected]7468ac522014-03-12 23:35:571743def GetPreferredTryMasters(project, change):
mohan.reddyf21db962014-10-16 12:26:471744 import re
[email protected]4ce995ea2012-06-27 02:13:101745 files = change.LocalPaths()
1746
Paweł Hajdan, Jref2afd42015-01-07 15:59:521747 import os
1748 import json
1749 with open(os.path.join(
1750 change.RepositoryRoot(), 'testing', 'commit_queue', 'config.json')) as f:
1751 cq_config = json.load(f)
1752 cq_trybots = cq_config.get('trybots', {})
1753 builders = cq_trybots.get('launched', {})
1754 for master, master_config in cq_trybots.get('triggered', {}).iteritems():
1755 for triggered_bot in master_config:
1756 builders.get(master, {}).pop(triggered_bot, None)
[email protected]911753b2012-08-02 12:11:541757
Paweł Hajdan, Jr4026dbc2015-01-14 09:22:321758 # Explicitly iterate over copies of dicts since we mutate them.
1759 for master in builders.keys():
1760 for builder in builders[master].keys():
1761 # Do not trigger presubmit builders, since they're likely to fail
1762 # (e.g. OWNERS checks before finished code review), and we're
1763 # running local presubmit anyway.
1764 if 'presubmit' in builder:
1765 builders[master].pop(builder)
1766
Paweł Hajdan, Jref2afd42015-01-07 15:59:521767 return builders